15

I have a small project in .NET 6 that contains minimal APIs like that one

app.MapGet("/clients",
     async (IClientRepository repo) =>
     {
          var results = await repo.GetClientsAsync();
          return mapper.Map<IEnumerable<ClientModel>>(results);
     });

In the SwaggerUI I can use this API but I can't find a way to add description to it (although in the project settings I check for creating an API XML documentation).

enter image description here

How can I add the XML comment?

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
Enrico
  • 3,592
  • 6
  • 45
  • 102

5 Answers5

26

Currently support for Open API docs for minimal APIs is quite minimal and does not allow adding descriptions/summaries as far as I can see. There is a feature planned for .NET 7 to add descriptions. Also soon Swashbuckle should consider EndpointMetadata for annotations.

Also related issue.

UPD

With latest updates to Swashbuckle nuget packages and Swashbuckle.AspNetCore.Annotations you can add description to the endpoints:

builder.Services.AddSwaggerGen(opts => opts.EnableAnnotations());

app.MapGet("/weatherforecast", () =>
{
    // Implementation
})
.WithMetadata(new SwaggerOperationAttribute(summary: "Summary", description: "Descritption Test"));

// Or

app.MapGet("/weatherforecast1", [SwaggerOperation(summary: "Summary1", description: "Descritption Test1")] () =>
{
    // Implementation
});

UPD2

For .NET 7 and latest Swashbuckle.AspNetCore package WithDescription method also can be used:

builder.Services.AddSwaggerGen();
...

app.MapGet("/weatherforecast", () =>
{
    // implementation
})
.WithDescription("Some Method Description")
.WithOpenApi();

Or with EndpointDescriptionAttribute:

app.MapGet("/weatherforecast1", [EndpointDescription("Some Attribute description")] () =>
{
    // implementation
})
.WithOpenApi();
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 3
    I would like to add, that ``WithOpenApi`` method you can find in [Microsoft.AspNetCore.OpenApi](https://www.nuget.org/packages/Microsoft.AspNetCore.OpenApi/) NuGet package. – Philip Voloshin Aug 17 '22 at 17:01
  • 2
    The `WithOpenApi` extension method also supports setting the operation's description by passing a delegate like `operation => operation.Description = "foo"; return operation;`. It's a little bit more robust because you can modify the entire operation. – Safia Abdalla Sep 28 '22 at 21:02
  • While some of the provided solutions work for pieces of documentation (like summary and description), I can't seem to find any information on documenting parameters. Has anyone come across the appropriate way to add documentation for the parameters? – Xorcist Nov 16 '22 at 21:29
  • @Xorcist AFAIK .NET 7 should support swagger documentation from xml comments - you can try it. Or try marking parameters with `SwaggerParameterAttribute` from `Swashbuckle.AspNetCore.Annotations`. – Guru Stron Nov 16 '22 at 21:32
  • 1
    I found the route cause of the parameters not be documented (in my case). Turns out if the minimal api endpoint mapping is defined with .WithOpenApi() the parameters will not be processed, but if you take that method call off, everything works as expected. – Xorcist Nov 17 '22 at 19:30
  • Support XML-based OpenAPI docs for minimal APIs #39927 https://github.com/dotnet/aspnetcore/issues/39927 Is not in .Net 8 planning yet. – Michael Freidgeim Mar 20 '23 at 22:19
13

package Swashbuckle.AspNetCore.Annotations 6.3

...
builder.Services.AddSwaggerGen(c => c.EnableAnnotations());

var app = builder.build();

app.MapGet("/clients",
    [SwaggerOperation(
        Summary = "returns clients",
        Description = "more description on get `clients`")]
    [SwaggerResponse(200, "success")]
    [SwaggerResponse(500, "some failure")]
    async (IClientRepository repo) =>
    {
        var results = await repo.GetClientsAsync();
        return mapper.Map<IEnumerable<ClientModel>>(results);
    }).WithTags("Clients");

more examples here https://github.com/domaindrivendev/Swashbuckle.AspNetCore#enrich-operation-metadata

daggett
  • 26,404
  • 3
  • 40
  • 56
8

1. Install package

dotnet add package Swashbuckle.AspNetCore.Annotations

2. Write code

// Program.cs

builder.Services.AddSwaggerGen(x =>
{
  x.EnableAnnotations();
});

// app.MapGet("/hi", [SwaggerOperation(Summary = "summary001", Description = "description001 `adads`")] () => "Hi");

app.MapGet("/hi", () => "Hi")
  .WithMetadata(new SwaggerOperationAttribute("summary001", "description001"));

Result

enter image description here

bugggy
  • 156
  • 2
  • 10
2

you may use Extension Methods Which I think are more cleaner way to document API endpoints. This way you can define generic response methods for each endpoint.

For this you need to install the following packages :

Swashbuckle.AspNetCore and Swashbuckle.AspNetCore.Annotations

using Microsoft.AspNetCore.Authorization;
using Swashbuckle.AspNetCore.Annotations;


public static class MinimalAttributeExtensions
{
    public static RouteHandlerBuilder AllowAnonymous(this RouteHandlerBuilder endpoint)
    {
        endpoint.WithMetadata(new AllowAnonymousAttribute());
        return endpoint;
    }
    public static RouteHandlerBuilder Authorize(this RouteHandlerBuilder endpoint, string policy = null, string[] roles = null, params string[] schemes)
    {
        var authorizeAttribute = new AuthorizeAttribute();

        if (!string.IsNullOrEmpty(policy))
        {
            authorizeAttribute.Policy = policy;
        }

        if (roles != null && roles.Any())
        {
            authorizeAttribute.Roles = string.Join(',', roles);
        }

        if (schemes != null && schemes.Any())
        {
            authorizeAttribute.AuthenticationSchemes = string.Join(',', schemes);
        }

        endpoint.WithMetadata(authorizeAttribute);

        return endpoint;
    }
    public static RouteHandlerBuilder AddMetaData<T>(this RouteHandlerBuilder endpoint, string tag, string summary = null, string description = null)
    {
        endpoint.WithTags(tag);

        endpoint.WithMetadata(new SwaggerOperationAttribute(summary, description));

        endpoint.WithMetadata(new SwaggerResponseAttribute(200, type: typeof(T)))
                .WithMetadata(new SwaggerResponseAttribute(500, type: typeof(ErrorResponseModel)))
                .WithMetadata(new SwaggerResponseAttribute(400, type: typeof(ErrorResponseModel)))
                .WithMetadata(new SwaggerResponseAttribute(404, type: typeof(ErrorResponseModel)))
                .WithMetadata(new SwaggerResponseAttribute(422, type: typeof(ErrorResponseModel)))
                .WithMetadata(new SwaggerResponseAttribute(304, type: typeof(ErrorResponseModel)));

        return endpoint;
    }
    public static RouteHandlerBuilder AddMetaData(this RouteHandlerBuilder endpoint, string tag, string summary = null, string description = null)
    {
        endpoint.WithTags(tag);

        endpoint.WithMetadata(new SwaggerOperationAttribute(summary, description));

        endpoint.WithMetadata(new SwaggerResponseAttribute(500, type: typeof(ErrorResponseModel)))
                .WithMetadata(new SwaggerResponseAttribute(400, type: typeof(ErrorResponseModel)))
                .WithMetadata(new SwaggerResponseAttribute(404, type: typeof(ErrorResponseModel)))
                .WithMetadata(new SwaggerResponseAttribute(422, type: typeof(ErrorResponseModel)))
                .WithMetadata(new SwaggerResponseAttribute(304, type: typeof(ErrorResponseModel)));

        return endpoint;
    }
}

following is an example of how to use these extension Methods:

app.MapGet(“/books”, async (BooksDB db) =>
{
    return await db.Books.ToListAsync()
})
.Authorize(policy : "AdminOnly", roles : new string[] {1,2}, schemes: "Bearer")
.AddMetaData<List<Book>>
(
    tag : "Books",
    summary : "Get All Books",
    description : "Get All Books in List, Roles Allowed => Admin Only"
);

The .AddMetaData<T> here represents the response model for success, this will also add to the response documentation of this endpoint. In this case it is List<Book>.

BNG016
  • 164
  • 1
  • 7
1

You may use this guide. It worked for me using Swashbuckle. There are extension methods that come with minimal APIs. Here is how it looks:

app.MapGet(“/books”, async (BooksDB db) =>
await db.Books.ToListAsync()
)
.Produces<List<Book>>(StatusCodes.Status200OK)
.WithName(“GetAllBooks”).WithTags(“Getters”);
Andrey R
  • 19
  • 1