Description
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.