dotnet-openapi
ASP.NET Core OpenAPI - the document and the docs UI
OpenAPI is two separate concerns that get conflated: producing a faithful machine-readable description of the API, and rendering that description as something a human can click through. This skill owns both. The endpoint declarations the document is generated from - route groups, filters, .WithName(), the typed results - belong to dotnet-minimal-api; here we assume those exist and concentrate on turning them into an accurate spec and a usable UI. Floor is .NET 8 / C# 12.
The single discipline that runs through everything below: the document is generated, never hand-written. You shape the endpoints and the metadata, and the pipeline derives the spec. A spec edited by hand drifts from the running code the first time anyone forgets to update it.
Pick one generator, by framework floor
- On .NET 8, use Swashbuckle -
AddSwaggerGen()at startup,UseSwagger()to expose the JSON. Reach for NSwag instead only when the same toolchain must also generate strongly-typed clients (C# or TypeScript) from the spec; that client story is NSwag's reason to exist. For a service that just publishes a contract, Swashbuckle is the lighter default. - On .NET 9 and up, prefer the framework's own
Microsoft.AspNetCore.OpenApi:builder.Services.AddOpenApi()andapp.MapOpenApi(), which serves the document at/openapi/v1.json. It is maintained in lockstep with the framework, carries no third-party dependency, and generates at build or first request without Swashbuckle's reflection overhead. This is the choice for any new .NET 9+ service. - Do not run two generators side by side, and do not migrate an existing project's generator without a concrete reason - a project already on Swashbuckle stays on Swashbuckle until there's a payoff. Match what the repo already does.