Skip to content

Update ProducesResponseTypeAttribute to support setting content types for the defined response #34542

Closed
@DamianEdwards

Description

@DamianEdwards

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.

Metadata

Metadata

Assignees

Labels

Priority:1Work that is critical for the release, but we could probably ship withoutarea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcenhancementThis issue represents an ask for new feature or an enhancement to an existing onefeature-minimal-actionsController-like actions for endpoint routingold-area-web-frameworks-do-not-use*DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions