dotnet / dotnet/aspnetcore

Support Content Negotiation in EndpointMetadataApiDescriptionProvider

Open
#60,590 0 comments 2 reactions 0 assignees View on GitHub
area-mvc
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Is your feature request related to a problem? Please describe the problem.

For a variety of reasons, I want content negotiation in my API. Specifically I want my routes to be able to return different Schemas for different media types. I **know** that actually doing the serialization is not something that is going to work out of the box but we already many examples where in Minimal API we can negotiate a JSON or an XML serialization of the object, and its absolutely no different (other than wiring up thing so its not _onerous_) to return different schemas serialized in different ways.

In my case, I'm working with Fast Endpoints and the Swagger generation is handled by NSwag, but I've tracked the source of "why doesn't this work" to EndpointMetadataApiDescriptionProvider. An example of what I want to have is:

``` csharp
public class GetById : Endpoint
public override void Configure()
{
Get(GetUserByIdRequest.Route);
Description(builder =>
{
builder
.Produces((int)HttpStatusCode.OK, "application/json", "application/vnd.example.user+json")
.Produces((int)HttpStatusCode.OK, "application/vnd.example.summary+json")
.Produces((int)HttpStatusCode.NotFound)
.ProducesProblemFE();
});
}
}
```

So my method returns a `UserAggregate` but the serialization has 3 media types and 2 different schemas, and I know I can convert `UserAggregate` into then both.

The issue arises here:
https://github.com/dotnet/aspnetcore/blob/e01e85ffeb346954da05b34b6a82f73d7da93d47/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs#L378-L381

The code assumes that you can only have one response for a particular status code, which is not true. What's also annoying is that you would expect these two things to be the same:

``` csharp
public class GetById : Endpoint
public override void Configure()
{
Get(GetUserByIdRequest.Route);
Description(builder =>
{
builder
.Produces((int)HttpStatusCode.OK, "application/json", "application/vnd.example.user+json")
.Produces((int)HttpStatusCode.NotFound)
.ProducesProblemFE();
});
}
}
```
and
``` csharp
public class GetById : Endpoint
public override void Configure()
{
Get(GetUserByIdRequest.Route);
Description(builder =>
{
builder
.Produces((int)HttpStatusCode.OK, "application/json")
.Produces((int)HttpStatusCode.OK, "application/vnd.example.user+json")
.Produces((int)HttpStatusCode.NotFound)
.ProducesProblemFE();
});
}
}
```
but they are not. In the second instance only one media type ends up in the generated swagger. You could argue, "then why do it" but the second is arguably cleaner

### Describe the solution you'd like

I would like to have some mechanism whereby I can have multiple response types for a give status code. From what I've looked at in NSwag, for example, it shouldn't be a problem to generate the swagger.

I assume there is some reason other than "you're never going to need it" for this restriction so maybe an explicit opt-in per document or per route is the way to go but I'd really like to see it in there.

### Additional context

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.