Generování dokumentů OpenAPI
Balíček Microsoft.AspNetCore.OpenApi
poskytuje integrovanou podporu generování dokumentů OpenAPI v ASP.NET Core. Balíček obsahuje následující funkce:
- Podpora generování dokumentů OpenAPI za běhu a přístup k nim prostřednictvím koncového bodu v aplikaci
- Podpora rozhraní API transformátoru, která umožňují upravovat vygenerovaný dokument.
- Podpora generování více dokumentů OpenAPI z jedné aplikace
- Využívá podporu schématu JSON, kterou
System.Text.Json
poskytuje . - Je kompatibilní s nativní AoT.
Instalace balíčku
Microsoft.AspNetCore.OpenApi
Nainstalujte balíček:
V konzole Správce balíčků spusťte následující příkaz:
Install-Package Microsoft.AspNetCore.OpenApi -IncludePrerelease
Pokud chcete přidat podporu pro generování dokumentů OpenAPI v době sestavení, nainstalujte Microsoft.Extensions.ApiDescription.Server
balíček:
V konzole Správce balíčků spusťte následující příkaz:
Install-Package Microsoft.Extensions.ApiDescription.Server -IncludePrerelease
Konfigurace generování dokumentů OpenAPI
Následující kód:
- Přidá služby OpenAPI.
- Povolí koncový bod pro zobrazení dokumentu OpenAPI ve formátu JSON.
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Spusťte aplikaci a přejděte k https://localhost:<port>/openapi/v1.json
zobrazení vygenerovaného dokumentu OpenAPI.
Zahrnutí metadat OpenAPI do webové aplikace ASP.NET
Zahrnutí metadat OpenAPI pro koncové body
ASP.NET shromažďuje metadata z koncových bodů webové aplikace a používá ho k vygenerování dokumentu OpenAPI.
V aplikacích založených na kontroleru se metadata shromažďují z atributů, jako je [EndpointDescription]
, [HttpPost]
a [Produces]
.
V minimálních rozhraních API se metadata dají shromažďovat z atributů, ale můžou se také nastavit pomocí rozšiřujících metod a dalších strategií, jako je například vrácení TypedResults
z obslužných rutin tras.
Následující tabulka obsahuje přehled shromážděných metadat a strategií pro jeho nastavení.
Metadata | Atribut | Metoda rozšíření | Další strategie |
---|---|---|---|
Souhrn | [EndpointSummary] |
WithSummary |
|
description | [EndpointDescription] |
WithDescription |
|
značky | [Tags] |
WithTags |
|
operationId | [EndpointName] |
WithName |
|
parametry | [FromQuery] , [FromRoute] , , [FromHeader] [FromForm] |
||
popis parametru | [Description] |
||
requestBody | [FromBody] |
Accepts |
|
odpovědi | [Produces] , [ProducesProblem] |
Produces , ProducesProblem |
TypedResults |
Vyloučení koncových bodů | [ExcludeFromDescription] |
ExcludeFromDescription |
ASP.NET Core neshromažďuje metadata z komentářů dokumentu XML.
Následující části ukazují, jak do aplikace zahrnout metadata a přizpůsobit vygenerovaný dokument OpenAPI.
Shrnutí a popis
Souhrn a popis koncového bodu lze nastavit pomocí [EndpointSummary]
[EndpointDescription]
atributů nebo v minimálních rozhraních API pomocí WithSummary
metod rozšíření a WithDescription
metod.
[EndpointSummary]
: EndpointSummaryAttribute[EndpointDescription]
: EndpointDescriptionAttributeWithSummary
: WithSummaryWithDescription
: WithDescription
Následující ukázka ukazuje různé strategie nastavení souhrnů a popisů.
Všimněte si, že atributy jsou umístěny v metodě delegáta, a ne v aplikaci. MapGet – metoda
app.MapGet("/extension-methods", () => "Hello world!")
.WithSummary("This is a summary.")
.WithDescription("This is a description.");
app.MapGet("/attributes",
[EndpointSummary("This is a summary.")]
[EndpointDescription("This is a description.")]
() => "Hello world!");
značky
OpenAPI podporuje zadávání značek v každém koncovém bodu jako formu kategorizace.
V aplikacích založených na kontroleru se název kontroleru automaticky přidá jako značka na všech jeho koncových bodech, ale dá se přepsat pomocí atributu [Tags]
.
V minimálních rozhraních API je možné značky nastavit buď pomocí atributu [Tags]
WithTags
, nebo metody rozšíření.
[Tags]
: TagsAttributeWithTags
: WithTags
Následující ukázka ukazuje různé strategie nastavení značek.
app.MapGet("/extension-methods", () => "Hello world!")
.WithTags("todos", "projects");
app.MapGet("/attributes",
[Tags("todos", "projects")]
() => "Hello world!");
operationId
OpenAPI podporuje id operace v každém koncovém bodu jako jedinečný identifikátor nebo název operace.
V aplikacích založených na kontroleru lze id operace nastavit pomocí atributu [EndpointName]
.
V minimálníchrozhraních [EndpointName]
WithName
[EndpointName]
: EndpointNameAttributeWithName
: WithName
Následující ukázka ukazuje různé strategie nastavení operationId.
app.MapGet("/extension-methods", () => "Hello world!")
.WithName("FromExtensionMethods");
app.MapGet("/attributes",
[EndpointName("FromAttributes")]
() => "Hello world!");
parametry
OpenAPI podporuje přidávání poznámek k cestě, řetězci dotazu, hlavičce a cookie parametrům, které rozhraní API využívá.
Architektura odvodí typy parametrů požadavku automaticky na základě podpisu obslužné rutiny trasy.
Atribut [Description]
lze použít k zadání popisu parametru.
Následující ukázka ukazuje, jak nastavit popis parametru.
app.MapGet("/attributes",
([Description("This is a description.")] string name) => "Hello world!");
requestBody
Chcete-li definovat typ vstupů přenášených jako tělo požadavku, nakonfigurujte vlastnosti pomocí Accepts rozšiřující metody k definování typu objektu a typu obsahu, které jsou očekávány obslužnou rutinou požadavku. V následujícím příkladu koncový bod přijímá Todo
objekt v textu požadavku s očekávaným typem application/xml
obsahu .
app.MapPost("/todos/{id}", (int id, Todo todo) => ...)
.Accepts<Todo>("application/xml");
Kromě Accepts rozšiřující metody může typ parametru popsat vlastní poznámku IEndpointParameterMetadataProvider implementací rozhraní. Následující typ například Todo
přidá poznámku, která vyžaduje text požadavku s typem application/xml
obsahu.
public class Todo : IEndpointParameterMetadataProvider
{
public static void PopulateMetadata(ParameterInfo parameter, EndpointBuilder builder)
{
builder.Metadata.Add(new AcceptsMetadata(["application/xml", "text/xml"], typeof(XmlBody)));
}
}
Pokud není zadána žádná explicitní poznámka, architektura se pokusí určit výchozí typ požadavku, pokud je v obslužné rutině koncového bodu parametr textu požadavku. Odvození používá k vytvoření poznámky následující heuristiku:
- Parametry textu požadavku, které se čtou z formuláře prostřednictvím atributu
[FromForm]
, jsou popsány pomocímultipart/form-data
typu obsahu. - Všechny ostatní parametry textu požadavku jsou popsány pomocí
application/json
typu obsahu. - Tělo požadavku je považováno za volitelné, pokud je nullable nebo pokud AllowEmpty je vlastnost nastavena na
FromBody
atribut.
Popis typů odpovědí
OpenAPI podporuje zadání popisu odpovědí vrácených z rozhraní API. Minimální rozhraní API podporují tři strategie nastavení typu odpovědi koncového bodu:
- Produces Prostřednictvím metody rozšíření na koncovém bodu.
- Prostřednictvím atributu
ProducesResponseType
v obslužné rutině trasy. - TypedResults Vrácením z obslužné rutiny trasy.
Metodu Produces
rozšíření lze použít k přidání Produces
metadat do koncového bodu. Pokud nejsou zadány žádné parametry, metoda rozšíření naplní metadata pro cílový typ pod stavovým kódem 200
a typem application/json
obsahu.
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.Produces<IList<Todo>>();
Použití TypedResults v implementaci obslužné rutiny trasy koncového bodu automaticky zahrnuje metadata typu odpovědi pro koncový bod. Například následující kód automaticky anotuje koncový bod odpovědí pod 200
stavovým kódem s typem application/json
obsahu.
app.MapGet("/todos", async (TodoDb db) =>
{
var todos = await db.Todos.ToListAsync();
return TypedResults.Ok(todos);
});
Nastavení odpovědí pro ProblemDetails
Při nastavování typu odpovědi pro koncové body, které mohou vrátit odpověď ProblemDetails, metodu ProducesProblem rozšíření nebo ProducesValidationProblem TypedResults.Problem lze použít k přidání příslušné poznámky k metadatům koncového bodu.
Pokud některá z těchto strategií neposkytuje žádné explicitní poznámky, architektura se pokusí určit výchozí typ odpovědi prozkoumáním podpisu odpovědi. Tato výchozí odpověď se vyplní pod stavový 200
kód v definici OpenAPI.
Více typů odpovědí
Pokud koncový bod může v různých scénářích vracet různé typy odpovědí, můžete zadat metadata následujícími způsoby:
Volejte metodu Produces rozšíření několikrát, jak je znázorněno v následujícím příkladu:
app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) => await db.Todos.FindAsync(id) is Todo todo ? Results.Ok(todo) : Results.NotFound()) .Produces<Todo>(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound);
Použijte
Results<TResult1,TResult2,TResultN>
v podpisu a TypedResults v textu obslužné rutiny, jak je znázorněno v následujícím příkladu:app.MapGet("/book{id}", Results<Ok<Book>, NotFound> (int id, List<Book> bookList) => { return bookList.FirstOrDefault((i) => i.Id == id) is Book book ? TypedResults.Ok(book) : TypedResults.NotFound(); });
Typy
Results<TResult1,TResult2,TResultN>
sjednocení deklarují, že obslužná rutina trasy vrací několikIResult
konkrétních typů a jakýkoli z těchto typů, které implementujíIEndpointMetadataProvider
, přispívají k metadatům koncového bodu.Typy sjednocení implementují implicitní operátory přetypování. Tyto operátory umožňují kompilátoru automaticky převést typy zadané v obecných argumentech na instanci sjednocovacího typu. Tato funkce má přidanou výhodu poskytování kontroly času kompilace, že obslužná rutina trasy vrací pouze výsledky, které deklaruje. Pokus o vrácení typu, který není deklarován jako jeden z obecných argumentů, aby výsledkem
Results<TResult1,TResult2,TResultN>
byla chyba kompilace.
Vyloučení koncových bodů z vygenerovaného dokumentu
Ve výchozím nastavení jsou všechny koncové body definované v aplikaci zdokumentované ve vygenerovaném souboru OpenAPI. Minimální rozhraní API podporují dvě strategie vyloučení daného koncového bodu z dokumentu OpenAPI pomocí:
Následující ukázka ukazuje různé strategie vyloučení daného koncového bodu z vygenerovaného dokumentu OpenAPI.
app.MapGet("/extension-method", () => "Hello world!")
.ExcludeFromDescription();
app.MapGet("/attributes",
[ExcludeFromDescription]
() => "Hello world!");
Zahrnutí metadat OpenAPI pro datové typy
Třídy nebo záznamy jazyka C# používané v těle požadavku nebo odpovědi jsou reprezentovány jako schémata v vygenerovaném dokumentu OpenAPI. Ve výchozím nastavení jsou ve schématu reprezentovány pouze veřejné vlastnosti, ale existují JsonSerializerOptions také vlastnosti schématu pro pole.
Pokud je nastavena PropertyNamingPolicy na camel-case (to je výchozí v ASP.NET webových aplikací), názvy vlastností ve schématu jsou velbloudí forma názvu třídy nebo záznamu vlastnosti. Lze JsonPropertyNameAttribute použít u jednotlivé vlastnosti k určení názvu vlastnosti ve schématu.
typ a formát
Knihovna schémat JSON mapuje standardní typy C# na OpenAPI type
a format
následujícím způsobem:
Typ jazyka C# | OpenAPI type |
OpenAPI format |
---|---|---|
int | integer | int32 |
long | integer | int64 |
short | integer | int16 |
byte | integer | uint8 |
float (číslo s plovoucí řádovou čárkou) | Číslo | float (číslo s plovoucí řádovou čárkou) |
double | Číslo | double |
decimal | Číslo | double |
bool | boolean | |
string | string | |
char | string | char |
byte[] | string | byte |
DateTimeOffset | string | date-time |
DateOnly | string | datum |
TimeOnly | string | čas |
Identifikátor URI | string | uri |
Guid | string | Uuid |
objekt | vynechal | |
dynamic | vynechal |
Všimněte si, že objekty a dynamické typy nemají v OpenAPI definovaný žádný typ, protože můžou obsahovat data libovolného typu, včetně primitivních typů, jako je int nebo string.
Lze type
jej format
také nastavit pomocí schématu Transformer. Můžete například chtít format
, aby desetinné typy byly decimal
místo double
.
Přidání metadat pomocí atributů
ASP.NET používá metadata z atributů ve vlastnostech třídy nebo záznamu k nastavení metadat odpovídajících vlastností generovaného schématu.
Následující tabulka shrnuje atributy z System.ComponentModel
oboru názvů, které poskytují metadata pro vygenerované schéma:
Atribut | Popis |
---|---|
DescriptionAttribute | description Nastaví vlastnost ve schématu. |
RequiredAttribute | Označí vlastnost jako required ve schématu. |
DefaultValueAttribute | default Nastaví hodnotu vlastnosti ve schématu. |
RangeAttribute | minimum Nastaví celočíselnou nebo číselnou hodnotu a maximum hodnotu. |
MinLengthAttribute | minLength Nastaví řetězec. |
MaxLengthAttribute | maxLength Nastaví řetězec. |
RegularExpressionAttribute | pattern Nastaví řetězec. |
Všimněte si, že v aplikacích založených na kontroleru tyto atributy přidávají do operace filtry, které ověří, že všechna příchozí data splňují omezení. V minimálních rozhraních API tyto atributy nastavují metadata ve vygenerovaném schématu, ale ověření musí být provedeno explicitně prostřednictvím filtru koncového bodu, v logice obslužné rutiny trasy nebo prostřednictvím balíčku třetí strany.
Další zdroje metadat pro vygenerovaná schémata
povinné
Vlastnosti lze také označit jako required
požadovaný modifikátor.
enum
Typy výčtů v jazyce C# jsou celočíselné, ale dají se reprezentovat jako řetězce ve formátu JSON pomocí a JsonConverterAttribute JsonStringEnumConverter. Pokud je typ výčtu reprezentován jako řetězec ve formátu JSON, vygenerované schéma bude mít enum
vlastnost s řetězcovými hodnotami výčtu.
Typ výčtu bez přípony JsonConverterAttribute bude definován jako type: integer
ve vygenerovaném schématu.
Poznámka: Nenastavuje AllowedValuesAttribute enum
hodnoty vlastnosti.
nullable
Vlastnosti definované jako hodnota s možnou hodnotou null nebo odkazovým typem mají nullable: true
ve vygenerovaném schématu. To je konzistentní s výchozím chováním System.Text.Json deserializátoru, který přijímá null
jako platnou hodnotu pro vlastnost s možnou hodnotou null.
additionalProperties
Schémata se generují bez kontrolního výrazu additionalProperties
ve výchozím nastavení, což znamená výchozí hodnotu true
. To je konzistentní s výchozím chováním deserializátoru System.Text.Json , který bezobslužně ignoruje další vlastnosti v objektu JSON.
Pokud by další vlastnosti schématu měly mít pouze hodnoty určitého typu, definujte vlastnost nebo třídu jako Dictionary<string, type>
. Typ klíče pro slovník musí být string
. Tím se vygeneruje schéma s určením additionalProperties
schématu pro typ jako požadované typy hodnot.
Metadata pro polymorfní typy
JsonPolymorphicAttribute Pomocí atributů JsonDerivedTypeAttribute nadřazené třídy určete diskriminující pole a podtypy pro polymorfní typ.
Přidá JsonDerivedTypeAttribute diskriminující pole do schématu pro každou podtřídu s výčtem určující specifickou diskriminující hodnotu podtřídy. Tento atribut také upraví konstruktor každé odvozené třídy tak, aby nastavil nediskriminační hodnotu.
Abstraktní třída s atributem JsonPolymorphicAttribute discriminator
má pole ve schématu, ale konkrétní třída s atributem JsonPolymorphicAttribute discriminator
nemá pole. OpenAPI vyžaduje, aby diskriminující vlastnost byla povinnou vlastností ve schématu, ale vzhledem k tomu, že diskriminující vlastnost není definována v konkrétní základní třídě, schéma nemůže obsahovat discriminator
pole.
Přidání metadat pomocí transformátoru schématu
Transformátor schématu lze použít k přepsání všech výchozích metadat nebo k vygenerovanému schématu přidat další metadata, například example
hodnoty. Další informace najdete v tématu Použití transformátorů schématu.
Možnosti přizpůsobení generování dokumentů OpenAPI
Následující části ukazují, jak přizpůsobit generování dokumentů OpenAPI.
Přizpůsobení názvu dokumentu OpenAPI
Každý dokument OpenAPI v aplikaci má jedinečný název. Výchozí název dokumentu, který je registrován, je v1
.
builder.Services.AddOpenApi(); // Document name is v1
Název dokumentu lze upravit předáním názvu jako parametru AddOpenApi
volání.
builder.Services.AddOpenApi("internal"); // Document name is internal
Název dokumentu se zobrazí na několika místech v implementaci OpenAPI.
Při načítání vygenerovaného dokumentu OpenAPI je název dokumentu zadaný jako documentName
argument parametru v požadavku. Následující žádosti tyto dokumenty a dokumenty vyřeší v1
internal
.
GET http://localhost:5000/openapi/v1.json
GET http://localhost:5000/openapi/internal.json
Přizpůsobení verze OpenAPI vygenerovaného dokumentu
Ve výchozím nastavení vytvoří generování dokumentů OpenAPI dokument, který vyhovuje specifikaci OpenAPI verze 3.0. Následující kód ukazuje, jak upravit výchozí verzi dokumentu OpenAPI:
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi2_0;
});
Přizpůsobení trasy koncového bodu OpenAPI
Ve výchozím nastavení koncový bod OpenAPI zaregistrovaný prostřednictvím volání pro MapOpenApi
zveřejnění dokumentu na koncovém /openapi/{documentName}.json
bodu. Následující kód ukazuje, jak přizpůsobit trasu, ve které je dokument OpenAPI zaregistrovaný:
app.MapOpenApi("/openapi/{documentName}/openapi.json");
Je možné, ale nedoporučuje se odebrat documentName
parametr trasy z trasy koncového bodu. documentName
Když se parametr trasy odebere ze trasy koncového bodu, architektura se pokusí přeložit název dokumentu z parametru dotazu. Nezadávaní documentName
trasy nebo dotazu může vést k neočekávanému chování.
Přizpůsobení koncového bodu OpenAPI
Vzhledem k tomu, že dokument OpenAPI se obsluhuje prostřednictvím koncového bodu obslužné rutiny trasy, je pro koncový bod OpenAPI k dispozici veškeré přizpůsobení, které je dostupné standardním minimálním koncovým bodům.
Omezení přístupu k dokumentům OpenAPI autorizovaným uživatelům
Koncový bod OpenAPI ve výchozím nastavení nepovoluje žádné kontroly autorizace. U dokumentu OpenAPI se ale dají použít kontroly autorizace. V následujícím kódu je přístup k dokumentu OpenAPI omezen na ty, které mají tester
roli:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization(o =>
{
o.AddPolicy("ApiTesterPolicy", b => b.RequireRole("tester"));
});
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi()
.RequireAuthorization("ApiTesterPolicy");
app.MapGet("/", () => "Hello world!");
app.Run();
Dokument OpenAPI vygenerovaný v mezipaměti
Dokument OpenAPI se znovu vygeneruje při každém odeslání požadavku na koncový bod OpenAPI. Regenerace umožňuje transformátorům začlenit do provozu dynamický stav aplikace. Například opětovné vygenerování požadavku s podrobnostmi o kontextu HTTP. Pokud je to možné, dokument OpenAPI je možné uložit do mezipaměti, aby se zabránilo spuštění kanálu generování dokumentů na každém požadavku HTTP.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(policy => policy.Expire(TimeSpan.FromMinutes(10)));
});
builder.Services.AddOpenApi();
var app = builder.Build();
app.UseOutputCache();
app.MapOpenApi()
.CacheOutput();
app.MapGet("/", () => "Hello world!");
app.Run();
Transformátory dokumentů OpenAPI
Tato část ukazuje, jak přizpůsobit dokumenty OpenAPI pomocí transformátorů.
Přizpůsobení dokumentů OpenAPI pomocí transformátorů
Transformátory poskytují rozhraní API pro úpravu dokumentu OpenAPI s uživatelsky definovanými přizpůsobeními. Transformátory jsou užitečné pro scénáře, jako jsou:
- Přidání parametrů do všech operací v dokumentu
- Úprava popisů parametrů nebo operací
- Přidání informací nejvyšší úrovně do dokumentu OpenAPI
Transformátory spadají do tří kategorií:
- Transformátory dokumentů mají přístup k celému dokumentu OpenAPI. Ty se dají použít k provádění globálních úprav dokumentu.
- Provozní transformátory platí pro každou jednotlivou operaci. Každá jednotlivá operace je kombinací cesty a metody HTTP. Ty se dají použít k úpravě parametrů nebo odpovědí na koncové body.
- Transformátory schématu se vztahují na každé schéma v dokumentu. Můžete je použít k úpravě schématu těla požadavků nebo odpovědí nebo jakýchkoli vnořených schémat.
Transformátory lze zaregistrovat do dokumentu voláním AddDocumentTransformer
metody na objektu OpenApiOptions
. Následující fragment kódu ukazuje různé způsoby registrace transformátorů do dokumentu:
- Zaregistrujte transformátor dokumentu pomocí delegáta.
- Registrace transformátoru dokumentu pomocí instance
IOpenApiDocumentTransformer
. - Zaregistrujte transformátor dokumentu pomocí DI-aktivovaného
IOpenApiDocumentTransformer
. - Zaregistrujte transformátor operace pomocí delegáta.
- Registrace transformátoru operace pomocí instance
IOpenApiOperationTransformer
. - Registrace provozního transformátoru pomocí DI-aktivovaného
IOpenApiOperationTransformer
. - Zaregistrujte transformátor schématu pomocí delegáta.
- Registrace transformátoru schématu pomocí instance
IOpenApiSchemaTransformer
. - Registrace transformátoru schématu pomocí DI-aktivovaného
IOpenApiSchemaTransformer
.
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer((document, context, cancellationToken)
=> Task.CompletedTask);
options.AddDocumentTransformer(new MyDocumentTransformer());
options.AddDocumentTransformer<MyDocumentTransformer>();
options.AddOperationTransformer((operation, context, cancellationToken)
=> Task.CompletedTask);
options.AddOperationTransformer(new MyOperationTransformer());
options.AddOperationTransformer<MyOperationTransformer>();
options.AddSchemaTransformer((schema, context, cancellationToken)
=> Task.CompletedTask);
options.AddSchemaTransformer(new MySchemaTransformer());
options.AddSchemaTransformer<MySchemaTransformer>();
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Pořadí provádění pro transformátory
Transformátory se spouštějí v prvním pořadí podle registrace. V následujícím fragmentu kódu má transformátor dokumentu přístup k úpravám provedeným provozním transformátorem:
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.AddOperationTransformer((operation, context, cancellationToken)
=> Task.CompletedTask);
options.AddDocumentTransformer((document, context, cancellationToken)
=> Task.CompletedTask);
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Použití transformátorů dokumentů
Transformátory dokumentů mají přístup k kontextového objektu, který zahrnuje:
- Název upravovaného dokumentu.
- Seznam přidružených k danému
ApiDescriptionGroups
dokumentu. - Použitá
IServiceProvider
při generování dokumentu.
Transformátory dokumentů mohou také ztlumit dokument OpenAPI, který je generován. Následující příklad ukazuje transformátor dokumentu, který přidává některé informace o rozhraní API do dokumentu OpenAPI.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer((document, context, cancellationToken) =>
{
document.Info = new()
{
Title = "Checkout API",
Version = "v1",
Description = "API for processing checkouts from cart."
};
return Task.CompletedTask;
});
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Transformátory dokumentů aktivované službou můžou k úpravě aplikace využívat instance z DI. Následující ukázka ukazuje transformátor dokumentu, který používá IAuthenticationSchemeProvider
službu z ověřovací vrstvy. Zkontroluje, jestli jsou v aplikaci zaregistrovaná nějaká schémata související s nosnou knihovnou JWT, a přidá je do nejvyšší úrovně dokumentu OpenAPI:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
{
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
{
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
{
var requirements = new Dictionary<string, OpenApiSecurityScheme>
{
["Bearer"] = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer", // "bearer" refers to the header name here
In = ParameterLocation.Header,
BearerFormat = "Json Web Token"
}
};
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes = requirements;
}
}
}
Transformátory dokumentů jsou jedinečné pro instanci dokumentu, ke které jsou přidruženy. V následujícím příkladu transformátor:
- Zaregistruje požadavky související s ověřováním do
internal
dokumentu. - Ponechá
public
dokument nezměněný.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddOpenApi("internal", options =>
{
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
});
builder.Services.AddOpenApi("public");
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/world", () => "Hello world!")
.WithGroupName("internal");
app.MapGet("/", () => "Hello universe!")
.WithGroupName("public");
app.Run();
internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
{
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
{
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
{
// Add the security scheme at the document level
var requirements = new Dictionary<string, OpenApiSecurityScheme>
{
["Bearer"] = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer", // "bearer" refers to the header name here
In = ParameterLocation.Header,
BearerFormat = "Json Web Token"
}
};
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes = requirements;
// Apply it as a requirement for all operations
foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
{
operation.Value.Security.Add(new OpenApiSecurityRequirement
{
[new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }] = Array.Empty<string>()
});
}
}
}
}
Použití provozních transformátorů
Operace jsou jedinečné kombinace cest HTTP a metod v dokumentu OpenAPI. Při úpravě jsou užitečné provozní transformátory:
- Měly by být provedeny do každého koncového bodu v aplikaci, nebo
- Podmíněné použití u určitých tras.
Transformátory operací mají přístup k objektu kontextu, který obsahuje:
- Název dokumentu, do které operace patří.
- Přidružená
ApiDescription
k operaci. - Použitá
IServiceProvider
při generování dokumentu.
Například následující transformátor operace přidá 500
jako stavový kód odpovědi podporovaný všemi operacemi v dokumentu.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddOpenApi(options =>
{
options.AddOperationTransformer((operation, context, cancellationToken) =>
{
operation.Responses.Add("500", new OpenApiResponse { Description = "Internal server error" });
return Task.CompletedTask;
});
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Použití transformátorů schématu
Schémata jsou datové modely, které se používají v těle požadavků a odpovědí v dokumentu OpenAPI. Transformátory schématu jsou užitečné při úpravě:
- Mělo by být provedeno každé schéma v dokumentu, nebo
- Podmíněné použití na určitá schémata.
Transformátory schématu mají přístup k objektu kontextu, který obsahuje:
- Název dokumentu, do které schéma patří.
- Informace o typu JSON přidružené k cílovému schématu.
- Použitá
IServiceProvider
při generování dokumentu.
Například následující transformátor schématu format
nastaví desetinné typy místo decimal
double
:
using Microsoft.AspNetCore.OpenApi;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options => {
// Schema transformer to set the format of decimal to 'decimal'
options.AddSchemaTransformer((schema, context, cancellationToken) =>
{
if (context.JsonTypeInfo.Type == typeof(decimal))
{
schema.Format = "decimal";
}
return Task.CompletedTask;
});
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => new Body { Amount = 1.1m });
app.Run();
public class Body {
public decimal Amount { get; set; }
}
Další materiály
Minimální rozhraní API poskytují integrovanou podporu generování informací o koncových bodech v aplikaci prostřednictvím Microsoft.AspNetCore.OpenApi
balíčku. Zveřejnění vygenerované definice OpenAPI prostřednictvím vizuálního uživatelského rozhraní vyžaduje balíček třetí strany. Informace o podpoře rozhraní OPENAPI v rozhraních API založených na kontroleru najdete ve verzi tohoto článku v .NET 9.
Následující kód vygeneruje ASP.NET minimální šablona webového rozhraní API a používá OpenAPI:
using Microsoft.AspNetCore.OpenApi;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateTime.Now.AddDays(index),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();
app.Run();
internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
V předchozím zvýrazněném kódu:
Microsoft.AspNetCore.OpenApi
je vysvětleno v další části.- AddEndpointsApiExplorer : Nakonfiguruje aplikaci tak, aby používala Průzkumníka rozhraní API ke zjišťování a popisu koncových bodů s výchozími poznámkami.
WithOpenApi
přepisuje porovnávání výchozích poznámek vygenerovaných Průzkumníkem rozhraní API s poznámkami vytvořenými zMicrosoft.AspNetCore.OpenApi
balíčku. UseSwagger
přidá middleware Swaggeru.- UseSwaggerUI umožňuje vloženou verzi nástroje Swagger UI.
- WithName: Koncový IEndpointNameMetadata bod se používá pro generování propojení a považuje se za ID operace ve specifikaci OpenAPI daného koncového bodu.
WithOpenApi
je vysvětleno dále v tomto článku.
Microsoft.AspNetCore.OpenApi
Balíček NuGet
ASP.NET Core poskytuje Microsoft.AspNetCore.OpenApi
balíček pro interakci se specifikacemi OpenAPI pro koncové body. Balíček funguje jako propojení mezi modely OpenAPI definovanými v Microsoft.AspNetCore.OpenApi
balíčku a koncovými body definovanými v minimálních rozhraních API. Balíček poskytuje rozhraní API, které zkoumá parametry koncového bodu, odpovědi a metadata a vytváří typ anotace OpenAPI, který se používá k popisu koncového bodu.
Microsoft.AspNetCore.OpenApi
se přidá jako PackageReference do souboru projektu:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.*-*" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>
Při použití Swashbuckle.AspNetCore
s Microsoft.AspNetCore.OpenApi
, Swashbuckle.AspNetCore
6.4.0 nebo novější musí být použita. Microsoft.OpenApi
1.4.3 nebo novější se musí použít k využití konstruktorů kopírování při WithOpenApi
vyvolání.
Přidání poznámek OpenAPI ke koncovým bodům prostřednictvím WithOpenApi
Volání WithOpenApi
koncového bodu se přidá do metadat koncového bodu. Tato metadata můžou být následující:
- Spotřebované v balíčcích třetích stran, jako je Swashbuckle.AspNetCore.
- Zobrazí se v uživatelském rozhraní Swaggeru nebo ve vygenerovaném YAML nebo JSON pro definování rozhraní API.
app.MapPost("/todoitems/{id}", async (int id, Todo todo, TodoDb db) =>
{
todo.Id = id;
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
})
.WithOpenApi();
Úprava poznámky OpenAPI v WithOpenApi
Metoda WithOpenApi
přijímá funkci, kterou lze použít k úpravě anotace OpenAPI. Například v následujícím kódu se k prvnímu parametru koncového bodu přidá popis:
app.MapPost("/todo2/{id}", async (int id, Todo todo, TodoDb db) =>
{
todo.Id = id;
db.Todos.Add(todo);
await db.SaveChangesAsync();
return Results.Created($"/todoitems/{todo.Id}", todo);
})
.WithOpenApi(generatedOperation =>
{
var parameter = generatedOperation.Parameters[0];
parameter.Description = "The ID associated with the created Todo";
return generatedOperation;
});
Přidání ID operací do OpenAPI
ID operací se používají k jednoznačné identifikaci daného koncového bodu v OpenAPI. Metodu WithName
rozšíření lze použít k nastavení ID operace použité pro metodu.
app.MapGet("/todoitems2", async (TodoDb db) =>
await db.Todos.ToListAsync())
.WithName("GetToDoItems");
Alternativně OperationId
lze vlastnost nastavit přímo na anotaci OpenAPI.
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.WithOpenApi(operation => new(operation)
{
OperationId = "GetTodos"
});
Přidání značek do popisu OpenAPI
OpenAPI podporuje kategorizaci operací pomocí objektů značek. Tyto značky se obvykle používají k seskupení operací v uživatelském rozhraní Swaggeru. Tyto značky lze do operace přidat vyvoláním metody rozšíření WithTags na koncovém bodu s požadovanými značkami.
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync())
.WithTags("TodoGroup");
Případně můžete seznam OpenApiTags
nastavit na anotaci OpenAPI prostřednictvím WithOpenApi
metody rozšíření.
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.WithOpenApi(operation => new(operation)
{
Tags = new List<OpenApiTag> { new() { Name = "Todos" } }
});
Přidání souhrnu nebo popisu koncového bodu
Souhrn a popis koncového WithOpenApi
bodu můžete přidat vyvoláním metody rozšíření. V následujícím kódu jsou souhrny nastavené přímo na anotaci OpenAPI.
app.MapGet("/todoitems2", async (TodoDb db) => await db.Todos.ToListAsync())
.WithOpenApi(operation => new(operation)
{
Summary = "This is a summary",
Description = "This is a description"
});
Vyloučit popis OpenAPI
V následující ukázce /skipme
je koncový bod vyloučený z generování popisu OpenAPI:
using Microsoft.AspNetCore.OpenApi;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapGet("/swag", () => "Hello Swagger!")
.WithOpenApi();
app.MapGet("/skipme", () => "Skipping Swagger.")
.ExcludeFromDescription();
app.Run();
Označení rozhraní API jako zastaralé
Pokud chcete koncový bod označit jako zastaralý, nastavte Deprecated
vlastnost v poznámce OpenAPI.
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.WithOpenApi(operation => new(operation)
{
Deprecated = true
});
Popis typů odpovědí
OpenAPI podporuje zadání popisu odpovědí vrácených z rozhraní API. Minimální rozhraní API podporují tři strategie nastavení typu odpovědi koncového bodu:
Produces
Prostřednictvím metody rozšíření na koncovém bodu- Prostřednictvím atributu
ProducesResponseType
v obslužné rutině trasy TypedResults
Vrácením z obslužné rutiny trasy
Metodu Produces
rozšíření lze použít k přidání Produces
metadat do koncového bodu. Pokud nejsou zadány žádné parametry, metoda rozšíření naplní metadata pro cílový typ pod stavovým kódem 200
a typem application/json
obsahu.
app
.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.Produces<IList<Todo>>();
Použití TypedResults
v implementaci obslužné rutiny trasy koncového bodu automaticky zahrnuje metadata typu odpovědi pro koncový bod. Například následující kód automaticky anotuje koncový bod odpovědí pod 200
stavovým kódem s typem application/json
obsahu.
app.MapGet("/todos", async (TodoDb db) =>
{
var todos = await db.Todos.ToListAsync());
return TypedResults.Ok(todos);
});
Nastavení odpovědí pro ProblemDetails
Při nastavování typu odpovědi pro koncové body, které můžou vrátit odpověď ProblemDetails, metodu ProducesProblem ProducesValidationProblemrozšíření nebo TypedResults.Problem
lze použít k přidání příslušné poznámky k metadatům koncového bodu. Všimněte si, že ProducesProblem
metody a ProducesValidationProblem
metody rozšíření nelze použít se skupinami tras v .NET 8 a starších verzích.
Pokud neexistují žádné explicitní poznámky poskytované některou z výše uvedených strategií, architektura se pokusí určit výchozí typ odpovědi prozkoumáním podpisu odpovědi. Tato výchozí odpověď se vyplní pod stavový 200
kód v definici OpenAPI.
Více typů odpovědí
Pokud koncový bod může v různých scénářích vracet různé typy odpovědí, můžete zadat metadata následujícími způsoby:
Volejte metodu
Produces
rozšíření několikrát, jak je znázorněno v následujícím příkladu:app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) => await db.Todos.FindAsync(id) is Todo todo ? Results.Ok(todo) : Results.NotFound()) .Produces<Todo>(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound);
Použijte
Results<TResult1,TResult2,TResultN>
v podpisu aTypedResults
v textu obslužné rutiny, jak je znázorněno v následujícím příkladu:app.MapGet("/book{id}", Results<Ok<Book>, NotFound> (int id, List<Book> bookList) => { return bookList.FirstOrDefault((i) => i.Id == id) is Book book ? TypedResults.Ok(book) : TypedResults.NotFound(); });
Typy
Results<TResult1,TResult2,TResultN>
sjednocení deklarují, že obslužná rutina trasy vrací několikIResult
konkrétních typů a jakýkoli z těchto typů, které implementujíIEndpointMetadataProvider
, přispívají k metadatům koncového bodu.Typy sjednocení implementují implicitní operátory přetypování. Tyto operátory umožňují kompilátoru automaticky převést typy zadané v obecných argumentech na instanci sjednocovacího typu. Tato funkce má přidanou výhodu poskytování kontroly času kompilace, že obslužná rutina trasy vrací pouze výsledky, které deklaruje. Pokus o vrácení typu, který není deklarován jako jeden z obecných argumentů, aby výsledkem
Results<TResult1,TResult2,TResultN>
byla chyba kompilace.
Popis textu a parametrů požadavku
Kromě popisu typů vrácených koncovým bodem podporuje OpenAPI také přidávání poznámek ke vstupům spotřebovaným rozhraním API. Tyto vstupy spadají do dvou kategorií:
- Parametry, které se zobrazují v cestě, řetězci dotazu, hlavičkách nebo souborech cookie
- Data přenášená jako součást textu požadavku
Architektura odvodí typy parametrů požadavku v cestě, dotazu a řetězci hlavičky automaticky na základě podpisu obslužné rutiny trasy.
Chcete-li definovat typ vstupů přenášených jako tělo požadavku, nakonfigurujte vlastnosti pomocí Accepts
rozšiřující metody k definování typu objektu a typu obsahu, které jsou očekávány obslužnou rutinou požadavku. V následujícím příkladu koncový bod přijímá Todo
objekt v textu požadavku s očekávaným typem application/xml
obsahu .
app.MapPost("/todos/{id}", (int id, Todo todo) => ...)
.Accepts<Todo>("application/xml");
Kromě rozšiřující metody může typ parametru Accepts
popsat vlastní poznámku IEndpointParameterMetadataProvider
implementací rozhraní. Následující typ například Todo
přidá poznámku, která vyžaduje text požadavku s typem application/xml
obsahu.
public class Todo : IEndpointParameterMetadataProvider
{
public static void PopulateMetadata(ParameterInfo parameter, EndpointBuilder builder)
{
builder.Metadata.Add(new ConsumesAttribute(typeof(Todo), isOptional: false, "application/xml"));
}
}
Pokud není zadána žádná explicitní poznámka, architektura se pokusí určit výchozí typ požadavku, pokud je v obslužné rutině koncového bodu parametr textu požadavku. Odvození používá k vytvoření poznámky následující heuristiku:
- Parametry textu požadavku, které se čtou z formuláře prostřednictvím atributu
[FromForm]
, jsou popsány pomocímultipart/form-data
typu obsahu. - Všechny ostatní parametry textu požadavku jsou popsány pomocí
application/json
typu obsahu. - Tělo požadavku je považováno za volitelné, pokud je nullable nebo pokud
AllowEmpty
je vlastnost nastavena naFromBody
atribut.
Podpora správy verzí rozhraní API
Minimální rozhraní API podporují správu verzí rozhraní API prostřednictvím balíčku Asp.Versioning.Http. Příklady konfigurace správy verzí s minimálními rozhraními API najdete v úložišti správy verzí rozhraní API.
ASP.NET základní zdrojový kód OpenAPI na GitHubu
Další materiály
Minimální aplikace API může popsat specifikaci OpenAPI pro obslužné rutiny tras pomocí Swashbuckle.
Informace o podpoře rozhraní OPENAPI v rozhraních API založených na kontroleru najdete ve verzi tohoto článku v .NET 9.
Následující kód je typická aplikace ASP.NET Core s podporou OpenAPI:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new() { Title = builder.Environment.ApplicationName,
Version = "v1" });
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger(); // UseSwaggerUI Protected by if (env.IsDevelopment())
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json",
$"{builder.Environment.ApplicationName} v1"));
}
app.MapGet("/swag", () => "Hello Swagger!");
app.Run();
Vyloučit popis OpenAPI
V následující ukázce /skipme
je koncový bod vyloučený z generování popisu OpenAPI:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(); // UseSwaggerUI Protected by if (env.IsDevelopment())
}
app.MapGet("/swag", () => "Hello Swagger!");
app.MapGet("/skipme", () => "Skipping Swagger.")
.ExcludeFromDescription();
app.Run();
Popis typů odpovědí
Následující příklad používá předdefinované typy výsledků k přizpůsobení odpovědi:
app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound())
.Produces<Todo>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);
Přidání ID operací do OpenAPI
app.MapGet("/todoitems2", async (TodoDb db) =>
await db.Todos.ToListAsync())
.WithName("GetToDoItems");
Přidání značek do popisu OpenAPI
Následující kód používá značku seskupení OpenAPI:
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync())
.WithTags("TodoGroup");