-
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
Support WithApiDescription
extension method for minimal APIs
#40084
Comments
Proposed APIWe introduce a new collection of base types for describing an endpoint, its parameters, and its responses. namespace Microsoft.AspNetCore.Http;
public class EndpointApiDescription
{
public string EndpointName { get; set; }
public string? GroupName { get; set; }
public string HttpMethod { get; set; }
public string? EndpointDescription { get; set; }
public string[]? EndpointTags {get; set; }
public EndpointMetadataCollection Metadata { get; set; }
public Dictionary<string, EndpointApiParameter> Parameters = new();
public Dictionary<int, EndpointApiResponse> Responses = new();
public Dictionary<string, object?> Items = new();
}
public class EndpointApiParameter
{
public string Name { get; set; }
public Type ParameterType { get; set; }
public string? Description { get; set; }
public ParameterSource Source { get; set; }
public ParameterInfo ParameterInfo { get; set; }
public Dictionary<string, object?> Items = new();
public IReadOnlyList<string>? ContentTypes { get; set; }
}
public class EndpointApiResponse
{
public int? StatusCode { get; set; }
public string? Description { get; set; }
public Type? ResponseType { get; set; }
public IReadOnlyList<string>? ContentTypes { get; set; }
public Dictionary<string, object?> Items = new();
} We also introduce a new namespace Microsoft.AspNetCore.Http;
public enum ParameterSource
{
Path,
Query,
Header,
Body,
FormFile,
Services
} Finally, we provide an extension method for adding a delegate to modify the public static RouteHandlerBuilder WithApiDescription(this RouteHandlerBuilder builder, Action<EndpointApiDescription> configureDescription)
{
builder.WithMetadata(configureDescription);
return builder;
} Usage Examplesapp.MapGet("/todos/{id}", (int id) => ...)
.WithApiDescription(endpointApiDescription =>
{
apiDescription.Description = "This is a new description."
apiDescription.Parameters["id"].Items["Examples"] = 0;
apiDescription.Responses[200].ResponseType = typeof(Todo);
}); Alternative Designs#40676 outlines an alternative proposal for this API where instead of using the new types that have been defined above, we use the types defined in OpenAPI.NET library and all users to modify those as part of the syntax. Assuming we decide to pursue that proposal, the new APIs introduced here would be rendered moot. However, the new API will still allow us to validate whether or not this direction (or the alternative referenced) is the right direction to pursue. |
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:
|
What is the Items bag and why is it string -> object instead of object -> object |
Closing to pursue bigger dreams. |
@captainsafia do you still expect for this proposal to be reviewed? If not, let's remove the |
Summary
Minimal APIs currently support annotating endpoints with metadata that can be used to generated OpenAPI descriptions for a particular endpoint. Currently, this endpoint can be used to annotate endpoints with details about the request parameters and responses and descriptive details (tags, summaries, descriptions).
However, the OpenAPI spec provides support for a larger variety of annotations including ones that describe the parameters of an endpoint specifically (like examples for a particular parameter). There's also a matter of the fact that the OpenAPI specification can introduce new annotations at any time and we have to ensure that we are compatible.
These circumstances present the requirement for an API that allows the user to more flexibly describe the API associated with an endpoint.
Goals
Non-goals
Proposed Design Walkthrough
Let's say that the user wants to annotate the following endpoint with these details:
id
parameterTo make things a little bit more interesting, we'll also assume that the endpoint already contains annotations
using our currently supported patterns (extension methods and attributes) that we would like to override with our new strategy. This will help show how the two implementations can intersect.
The user will leverage a new extension method in the framework:
To annotate their API with the desired schema, the user will provide a function that takes an
EndpointApiDescription
, modifies the desired properties, and returns the modifiedEndpointApiDescription
.The
EndpointApiDescription
is a new class that represents the API description. It contains a mix of strongly-typed properties and anItems
bag that can be used to add/override arbitrary fields.The
EndpointApiDescription
in turn references two new types:EndpointApiParameter
andEndpointApiResponse
that follow a similar model.The
WithApDescription
will register theconfigureDescription
delegate that is provided and store it in the metadata of the targeted endpoint.This change will be coupled with some changes to the
EndpointMetadataApiDescriptionProvider
that will register the constructs produced by the provider onto the schema, call the usersconfigureDescription
method, and set the resultingEndpointApiDescription
onto the metadata for consumption by external libraries.This change will require that ecosystem libraries like Swashbuckle and NSwag respect the new
EndpointApiDescription
class and that some conventions be adopted around how certain properties are represented. For example, since theExamples
property is not supported as a strongly-typed field, conventions will need to be established around storing it indescription.Parameters["todo"].Items["Examples"]
.Back to the
WitApiDescription
method, behind the scenes it registers the delegate provided to the user as part of the metadata associated with the endpoint.The
configureSchema
method is called from theEndpointMetadataApiDescriptionProvider
after the API description has been constructed. In order to support this scenario, we will need to refactor the provider so that the following logic can be invoked.The
CreateApiDescriptionFromSchema
maps the newEndpointApiDescription
type to the existingApiDescription
type by using the following mappings:GroupName
andRelativePath
EndpointApiDescription.Parameters
andEndpointApiDescription.Responses
get populated intoApiDescription.Properties
With this in mind, the previous flow for API generation looked like this:
To the following:
Unknowns
There are some considerations to be made around how this feature interacts with route groups. For now, it might be sufficient for our purposes to assume that the
WithApiDescription
method cannot be invoked on aRouteGroup
since API-descriptions are endpoint-specific descriptors.If we do want to provide support for
WithApiDescription
on route groups, we can work with one of two patterns:WithApiDescription
is invoked on every endpoint defined within a groupAlternatives Considered
Another design considered for this problem was a more builder-style approach for the
WithApiDescription
approach where in users could modify the API description using a set ofConfigureX
methods.Although this alternative does come with benefits, including, some of the drawbacks include:
The text was updated successfully, but these errors were encountered: