dotnet/aspnetcore

Epic: Minimal API - OpenAPI features

rafikiassumani-msft opened this issue · 3 comments

This issue covers the desired experience for minimal APIs integration with OpenAPI via metadata and ApiExplorer observing libraries like Swashbuckle and nSwag.

Issues (ASP.NET Core)

Priority One


Other

Issues (Swashbuckle)

Additional context

The goal is to allow for minimal APIs to support having metadata specified (manually in .NET 6, either imperatively via extension methods or declaratively via attributes, potentially automatically based on endpoint implementation and/or convention in a release after .NET 6) that enables the following to be satisfied by default when an OpenAPI library is also configured (i.e. without the OpenAPI library requiring further manual configuration):

  • Endpoint name that maps to operationId in generated OpenAPI documents.
    • Note the endpoint name is also used when using LinkGenerator to generate URL/links for endpoints
  • Endpoint group name that maps to the document name in generated OpenAPI documents (typically used for versioning, e.g. "v1", "v2")
  • Metadata indicating that the API should be excluded/ignored from OpenAPI document generation
  • Metadata indicating what response types a method produces, where each response is the combination of:
    • One status code
    • One or more content types, e.g. "application/json"
    • An optional schema per content type

Examples

Example of what specifying the metadata imperatively could look like:

app.MapGet("/admin", () => "For admins only")
   .WithName("AdminDetails")
   .RequiresAuthorization("Admins")
   .ExcludeFromApiExplorer();

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")
    .WithGroupName("v1")
    .ProducesValidationProblem()
    .Produces<Todo>(StatusCodes.Status201Created);

Example of what specifying the metadata declaratively could look like:

app.MapGet("/admin", AdminDetails);
app.MapPost("/todos-attr-desc", AddTodo);

[Authorized(Policy = "Admins")]
[ExcludeFromApiExplorer]
string AdminDetails()
{
    return "For admins only";
}

[EndpointGroupName("v1")]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest, "application/problem+json")]
[ProducesResponseType(typeof(Todo), StatusCodes.Status201Created)]
async Task<IResult> AddTodo(Todo todo, TodoDb db)
{
    if (!MinimalValidation.TryValidate(todo, out var errors))
        return Results.ValidationProblem(errors);

    db.Todos.Add(todo);
    await db.SaveChangesAsync();

    return Results.Created($"/todos/{todo.Id}", todo);
}

I guess we need to understand how this affects MVC routes as well? I assume it will conflict. We need to figure out what happens when somebody does:

app.MapControlles().WithName("DontDoThis").ProducesValidationProblem();

I am closing this issue as I moved the unfinished items to the following issue for .NET7 Planning: #37098