-
Notifications
You must be signed in to change notification settings - Fork 10.2k
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
Unable to set route description or summary with minimal api #37906
Comments
Triage: We are planning to fix this as part of .NET7 issue #37098 |
@rafikiassumani-msft thanks for the update. Is there any entry point where we could implement the functionality to add an endpoint description ourself till the gap is potentially closed in .NET7 ? Any hint would be highly appreciated. |
This should light up when using You can see some examples of working around it in this repo of mine: https://github.com/martincostello/api/search?q=SwaggerOperationAttribute |
@martincostello bam! thank you! I already thought we need to move back to mvc controllers. ;) |
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
Background and MotivationThe OpenAPI schema provides support for annotating properties with summaries, descriptions, and examples.
This PR introduces support for these annotations in minimal APIs via declarative and imperative approaches. It does not modify any of the logic in MVC though. That is supported by XML-doc parsing support in Swashbuckle which pulls the data above from XML docs on an action/endpoint. We are tracking #39927 to look at supporting this pattern for minimal APIs as well. Proposed APIDescription and Summarynamespace Microsoft.AspNetCore.Http.Metadata
{
public interface ISummaryMetadata
{
string Summary { get; }
}
public interface IDescriptionMetadata
{
string Description { get; }
}
}
namespace Microsoft.AspNetCore.Http
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate, Inherited = false, AllowMultiple = false)]
public sealed class SummaryAttribute : Attribute, ISummaryMetadata
{
public SummaryAttribute(string summary)
public string Summary { get; }
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate | AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
public sealed class DescriptionAttribute : Attribute, IDescriptionMetadata
{
public DescriptionAttribute(string description)
public string Description { get; }
}
} ExampleMetadatanamespace Microsoft.AspNetCore.Http.Metadata
{
public interface IExampleMetadata
{
string Summary { get; }
string Description { get; }
object? Value { get; }
string? ExternalValue { get; }
string? ParameterName { get; set; }
}
}
namespace Microsoft.AspNetCore.Http
{
[AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
public sealed class ExampleAttribute : Attribute, IExampleMetadata
{
public ExampleAttribute(string summary, string description, object value)
public ExampleAttribute(string summary, string description, string externalValue)
public string Description { get; }
public string Summary { get; }
public object? Value { get; }
public string? ExternalValue { get; }
public string? ParameterName { get; set; }
}
} Extension Methodsnamespace Microsoft.AspNetCore.Http
{
public static class OpenApiRouteHandlerBuilderExtensions
{
public static RouteHandlerBuilder WithResponseExample(
this RouteHandlerBuilder builder,
string summary,
string description,
object value)
public static RouteHandlerBuilder WithResponseExample(
this RouteHandlerBuilder builder,
string summary,
string description,
string externalValue)
public static RouteHandlerBuilder WithParameterExample(
this RouteHandlerBuilder builder,
string summary,
string description,
object value)
public static RouteHandlerBuilder WithParameterExample(
this RouteHandlerBuilder builder,
string summary,
string description,
string externalValue)
public static RouteHandlerBuilder WithDescription(this RouteHandlerBuilder builder, string description)
public static RouteHandlerBuilder WithSummary(this RouteHandlerBuilder builder, string summary)
} ApiExplorer Changesnamespace Microsoft.AspNetCore.Mvc.ApiExplorer;
public class ApiResponseType
{
public IEnumerable<IExampleMetadata>? Examples { get; set; }
public string? Description { get; set; }
}
public class ApiParameterDescription
{
public IEnumerable<IExampleMetadata>? Examples { get; set; }
public string? Description { get; set; }
} Usage Examplesvar app = WebApplication.Create(args);
// Add a summary to an endpoint
app
.MapGet("/todos/{id}", (int id, TodoService todos) => todos.Get(id))
.WithSummary("Resolves a Todo item from the backend service.")
// Add a description to an endpoint
app
.MapGet("/todos/{id}", (int id, TodoService todos) => todos.Get(id))
.WithDescription("""This endpoint returns a Todo given an ID.
If the request is unauthenticated then the backend API
will resolve a sample todo and issue a redirect to the
login page.""");
// Add a description to a parameter
app
.MapGet("/todos/{id}", ([Description("The ID of the todo...")]int id, TodoService todos) => todos.Get(id));
// Add an example to a parameter
app.MapGet("/todos/{id}",
([Example("An example for the provided parameter", "Some long description", 2)] int id, TodoService todos) => todos.Get(id));
// Add an example to a parameter via extension method
app
.MapGet("/todos/{id}", (int id, TodoService todos) => todos.Get(id))
.WithParameterExample("id", "An example for the provided parameter", "Some long description", 2);
// Add an example for the request body
app
.MapPost("/todos", (Todo todo, TodoService todos) => todos.CreateTodo(todo))
.WithParameterExample("Example of value todo", "When a todo is scheduled, the Todo...", new Todo() { Id = 1 })
.WithParameterExample("Example of externalValue todo", "When a todo is scheduled, the Todo...", "https://examples.com/foo/bar");
// Add an example for the response
app
.MapGet("/todos/{id}", (int id, TodoService todos) => todos.Get(id))
.WithResponseExample("This is a response with a value", "Some long description", new Todo() { Id = 1 })
.WithResponseExample("This is a response with an external value", "Some long description", "https://example.com/foo/bar"); Alternative Designs and Considerations
|
We held a little API review for this and decided to go in a different direction with this implementation. Supporting
With that in mind, we've opened #40084 to examine creating a unified extension method for endpoints that allows modifying all aspects of an API description. And, we've limited the scope of this change to what was strictly in the original issue, supporting descriptions and summaries in endpoints. So now the new API we're taking through review is: Interfaces and Classes namespace Microsoft.AspNetCore.Http.Metadata
{
public interface ISummaryMetadata
{
string Summary { get; }
}
public interface IDescriptionMetadata
{
string Description { get; }
}
}
namespace Microsoft.AspNetCore.Http
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate, Inherited = false, AllowMultiple = false)]
public sealed class SummaryAttribute : Attribute, ISummaryMetadata
{
public SummaryAttribute(string summary)
public string Summary { get; }
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate | AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
public sealed class DescriptionAttribute : Attribute, IDescriptionMetadata
{
public DescriptionAttribute(string description)
public string Description { get; }
}
} Extension Methods namespace Microsoft.AspNetCore.Http
{
public static class OpenApiRouteHandlerBuilderExtensions
{
public static RouteHandlerBuilder WithDescription(this RouteHandlerBuilder builder, string description)
public static RouteHandlerBuilder WithSummary(this RouteHandlerBuilder builder, string summary)
}
} Usage Examples app
.MapGet("/todos/{id}", [Summary("A summary)] (int id, TodoService todos) => todos.Get(id));
app
.MapGet("/todos/{id}", [Description("A description)] (int id, TodoService todos) => todos.Get(id));
app
.MapGet("/todos/{id}", (int id, TodoService todos) => todos.Get(id))
.WithSummary("Resolves a Todo item from the backend service.")
// Add a description to an endpoint
app
.MapGet("/todos/{id}", (int id, TodoService todos) => todos.Get(id))
.WithDescription("""This endpoint returns a Todo given an ID.
If the request is unauthenticated then the backend API
will resolve a sample todo and issue a redirect to the
login page."""); |
Is your feature request related to a problem? Please describe.
Hi, I am using the new minimal hosting model with dotnet 6 and I set up my endpoints like this:
Is there a way to set the summary of the route, so right next to the route -> underlined with red?
Is there a way to set the extended description of the route, so below the http method, in this case POST, and above the parameters section -> marked by the red arrow?
I already checked and there seem to only be the WithTags method or the AddMetaData where you could add EndpointNameMetadata
I think this feature is essential for providing a well structured and helpful api documentation.
Describe the solution you'd like
I would like to have the option to add the description either by having a dedicated method for that, so:
or to have attributes like the EndpointNameMetadata f.e.
EndpointDescriptionMetadata
which can be used to set the OpenApi description of that route and be passed to theWithMetadata()
methodThe text was updated successfully, but these errors were encountered: