dotnet/aspnetcore

Update `ProducesResponseTypeAttribute` to support setting content types for the defined response

DamianEdwards opened this issue · 1 comments

The Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute implements IApiResponseMetadataProvider today but does not support setting the content types associated with the response type defined by the attribute instance. This limitation means there is no way to specify the content type produced for specific status codes for a given endpoint, despite the OpenAPI specification supporting this.

Customers have indicated they have a need for this support in the OpenAPI library for ASP.NET Core, Swashbuckle too, see domaindrivendev/Swashbuckle.AspNetCore#1691

Take the following common example. A single endpoint can return either 400 Bad Request with a validation problem formatted as application/problem+json, or a 201 Created with the created resource formatted as application/json:

app.MapPost("/todos", async (Todo todo, TodoDb db) =>
    {
        if (!MinimalValidation.TryValidate(todo, out var errors))
            return Results.ValidationProblem(errors);

        db.Todos.Add(todo);
        await db.SaveChangesAsync();

        return Results.CreatedAtRoute("GetTodoById", new { todo.Id }, todo);
    })
    .WithName("AddTodo")
    .Produces<HttpValidationProblemDetails>(StatusCode.Status400BadRequest, "application/problem+json")
    .Produces<Todo>(StatusCodes.Status201Created, "application/json");

This would be represented in an OpenAPI document like this:

"/todos": {
    "post": {
        "tags": [
            "TodoApi"
        ],
        "requestBody": {
            "content": {
                "application/json": {
                    "schema": {
                        "$ref": "#/components/schemas/Todo"
                    }
                }
            }
        },
        "responses": {
            "201": {
                "description": "Success",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Todo"
                        }
                    }
                }
            },
            "400": {
                "description": "Bad Request",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/HttpValidationProblemDetails"
                        }
                    }
                }
            }
        }
    }
}

We should update Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute to support defining the content types associated with the declared response type, e.g.:

public class ProducesMetadataAttribute : ProducesResponseTypeAttribute, IApiResponseMetadataProvider
{
    public ProducesMetadataAttribute(int statusCode) : base(statusCode) { }
    public ProducesMetadataAttribute(Type type, int statusCode) : base(type, statusCode) { }
+   public ProducesMetadataAttribute(Type? type, int statusCode, string? contentType, params string[] additionalContentTypes) : base(statusCode) { }

+   public MediaTypeCollection ContentTypes { get; set; } = new();

-   void IApiResponseMetadataProvider.SetContentTypes(MediaTypeCollection contentTypes) { } 
+   public void SetContentTypes(MediaTypeCollection contentTypes) { }
}

This change would work in conjunction with #33924 to enable endpoints to describe the content types they return for each status code and response type. Endpoints that don't specify a content type should default to being described as returning application/json inline with the default minimal APIs behavior.

Thanks for contacting us.

We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.