-
Notifications
You must be signed in to change notification settings - Fork 10k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Description to ProducesResponseType (and others) for better OpenAPI documents #55656
Comments
Note: In case this proposal gets accepted, I would love to be the "main author" for getting this implemented in ASP.NET Core (Though help would definitely be welcome!). |
Consider us informed 😄 We'll happily accept a PR (once we have a branch for .NET |
@sander1095 Thanks for getting this issue together! The one gap I notice is that this proposal primarily targets the |
I am unfamiliar with using attributes in minimal API's, I thought it was all extension method based on the MapGet/MapPost/MapEtc.. methods. Description is already a first class citizen in minimal API. However, I have nothing against adding more OpenAPI description support in both Controllers and Minimal API's.😁 EDIT: I just realized that I got the the Description of an endpoint confused with the Description of a response. Woops! In case this is not supported yet in the minimal api model, I 100% believe it should be added! |
[API Review]
var app = WebApplication.Create();
app.MapGet("/todo", () => new Todo())
.Produces<Todo>(StatusCodes.Status200OK);
// Requires no new extension methods
app.MapGet("/todo", () => new Todo())
.WithMetadata(new ProducesResponseTypeMetadata(StatusCodes.Status200OK, typeof(Todo), ["application/json"]) { Description = "Get a todo item" });
// Requires new Produces overload that takes ProducesResponseTypeMetadata
app.MapGet("/todo", () => new Todo())
.Produces(new ProducesResponseTypeMetadata(StatusCodes.Status200OK, typeof(Todo), new[] { "application/json" }) { Description = "Get a todo item" }); |
// Assembly: Microsoft.AspNetCore.Mvc.Core
namespace Microsoft.AspNetCore.Mvc.ApiExplorer;
public interface IApiResponseMetadataProvider : IFilterMetadata
{
+ string? Description { get; }
} // Assembly: Microsoft.AspNetCore.Mvc.Core
namespace Microsoft.AspNetCore.Mvc;
public class ProducesAttribute : Attribute, IResultFilter, IOrderedFilter, IApiResponseMetadataProvider
{
+ public string? Description { get; set; }
} // Assembly: Microsoft.AspNetCore.Mvc.Core
namespace Microsoft.AspNetCore.Mvc;
public class ProducesResponseTypeAttribute : Attribute, IResultFilter, IOrderedFilter, IApiResponseMetadataProvider
{
+ public string? Description { get; set; }
} // Assembly: Microsoft.AspNetCore.Mvc.Abstractions
namespace Microsoft.AspNetCore.Mvc.ApiExplorer;
public class ApiResponseType
{
+ public string? Description { get; set; }
// Existing code here
} // Assembly: Microsoft.AspNetCore.Http.Abstractions;
namespace Microsoft.AspNetCore.Http.Metadata;
public interface IProducesResponseTypeMetadata
{
+ string? Description { get; }
} // Assembly: Microsoft.AspNetCore.Http.Abstractions;
namespace Microsoft.AspNetCore.Http;
public sealed class ProducesResponseTypeMetadata : IProducesResponseTypeMetadata
{
+ string? Description { get; init; }
} API Approved! |
@sander1095 The above API was approved in case you'd like to update your draft PR. Note: we're leaving the question on how to handle the |
Thanks Safia! I'll look into this. It seems like lots of @amcasey 's code suggestions are already part of my branch. My ongoing work can be seen here. I'm extremely excited to contribute to ASP.NET Core in this area! ❤️ |
Safia updated the PR description with new methods in
Which one is it? Please take a look at my work so you can give specific feedback :) main...sander1095:aspnetcore:main Also, could you help me with these issues? I read the docs about overloading public methods and I believe i've updated the code correctly, but I still get the following errors:
Should I simply use I do not know how to solve the 2nd issue :) One more question, if you wouldn't mind: Would you like me to write unit tests in all of these classes that receive the new Finally, could you give me some instructions on how I could test my changes? I'd love to create a new ASP.NET Core project locally and test out my changes with these new |
Hey, @sander1095! My comments on the API proposal were on behalf of the API reviewers as a group - @captainsafia is the best person to help you move this forward. |
That part of the API proposal was rejected because it would've been difficult to update the existing
This issue is happening because the var metadata = new ProducesResponseTypeMetadata(200, typeof(Todo), ["application/json"], "This is my description"); It is instantiated like this: var metadata = new ProducesResponseTypeMetadata(200, typeof(Todo), ["application/json"]) { Description = "This is my description");
For this and the other testing-related question, would you mind opening a draft PR with your change and we can iterate on testing there? |
@captainsafia Thanks for your swift reply! I'll do so when I get back from my holiday in a few weeks. 😁 Now that I got things running a bit more smoothly locally, it is easier to work on this issue and PR. |
Getting description support in MinimalAPIs would be great for us! |
@A-Stapleton I've created #57963 for this. I'm planning to create a PR during cc @captainsafia : Perhaps we can start a discussion in #57963 on what changes would be needed to add |
Background and Motivation
The purpose of this API Change is to make it easier for developers to add the
Description
properties to their OpenAPI documents using the[ProducesResponseType], [Produces] and [ProducesDefaultResponseType]
attributes in controller actions.Developers currently use these properties to enrich the OpenAPI document of the API. It tells the reader the possible return values from an endpoint, like a status code, response model type and content type:
See code + OpenAPI example
OpenAPI document is generated using NSwag (I used a JSON to YAML converter)
However, there is currently no way to map OpenAPIs
description
using attributes, which is the easiest way to enrich your methods with OpenAPI information which also works well with the OpenAPI analyzers.It's important to make it easy for developers to set up the
Description
property because this adds a lot of important information to a specific response. For example, if an API returnsHTTP 422
, it would be useful to add a description explaining why/when this error is returned. Without this, handling this error in the client becomes more difficult because the meaning is lost.There are other ways to set the
Description
right now, but I'm not a big fan of them. I explain why in Alternative designs below.I've wanted this feature in ASP.NET Core for a while. I've created this API proposal after talking to @captainsafia about this at the MVP Summit 2024, and she agreed that this would be a worthy addition. I had already created #54064 for this at some point. I hope the rest of the team/community agrees!
Proposed API
// Assembly: Microsoft.AspNetCore.Mvc.Core namespace Microsoft.AspNetCore.Mvc.ApiExplorer; public interface IApiResponseMetadataProvider : IFilterMetadata { + string? Description { get; } }
// Assembly: Microsoft.AspNetCore.Mvc.Core namespace Microsoft.AspNetCore.Mvc; public class ProducesAttribute : Attribute, IResultFilter, IOrderedFilter, IApiResponseMetadataProvider { + public string? Description { get; set; } }
// Assembly: Microsoft.AspNetCore.Mvc.Core namespace Microsoft.AspNetCore.Mvc; public class ProducesResponseTypeAttribute : Attribute, IResultFilter, IOrderedFilter, IApiResponseMetadataProvider { + public string? Description { get; set; } }
// Assembly: Microsoft.AspNetCore.Mvc.Abstractions namespace Microsoft.AspNetCore.Mvc.ApiExplorer; public class ApiResponseType { + public string? Description { get; set; } // Existing code here }
// Assembly: Microsoft.AspNetCore.Http.Abstractions; namespace Microsoft.AspNetCore.Http.Metadata; public interface IProducesResponseTypeMetadata { + string? Description { get; } }
// Assembly: Microsoft.AspNetCore.Http.Abstractions; namespace Microsoft.AspNetCore.Http; public sealed class ProducesResponseTypeMetadata : IProducesResponseTypeMetadata { + string? Description { get; private set; } }
Usage Examples
Alternative Designs
XML comments
An alternative design is to do nothing and use the built-in solution, which are XML comments:
This will fill the
description
properties with the values from the<response>
tags.However:
[ProducesResponseType]
(and the other ones mentioned above) and XML comments.<response>
can set a description for[ProducesDefaultResponseType]
To summarize: I do not think that XML comments is the correct one.
Library specific attributes
Both Swashbuckle.AspNetCore and NSwag have their own versions of
[ProducesResponseType]
called[SwaggerResponse]
that do support the OpenAPIDescription
property.However, there are several downsides to this:
[ProducesResponseType]
is library agnostic. By using[ProducesResponseType]
I could switch from Swashbuckle to NSwag and the OpenAPI document generation should keep working, which isn't guaranteed if I used a library specific attribute.[SwaggerResponse]
with[ProducesResponseType]
to set up response descriptions doesn't work. When[SwaggerResponse]
is used, all instances of[ProducesResponseType]
are ignored for that method.[SwaggerResponse]
for description support and others can still use[ProducesResponseType]
, which makes things more difficult to read because their method signature is different.[SwaggerResponse]
, which means I need to disable those warnings for specific methods, which is annoying and makes code more difficult to read.If ASP.NET Core's
[ProducesResponseType]
would support things like Description, the library-specific versions attributes might not be needed anymore, which makes it even easier to switch libraries in the future.Risks
Swashbuckle.AspNetCore's SwaggerResponse
[ProducesResponseType]
and already has its own Description property, which means that this change might cause some issues for them. However, .NET 9 won't ship Swashbuckle anymore by default, reducing the impact this has. Regardless, Swashbuckle's authors should be informed of this change.The text was updated successfully, but these errors were encountered: