Generowanie dokumentów OpenAPI
Pakiet Microsoft.AspNetCore.OpenApi
zapewnia wbudowaną obsługę generowania dokumentów OpenAPI w programie ASP.NET Core. Pakiet udostępnia następujące funkcje:
- Obsługa generowania dokumentów OpenAPI w czasie wykonywania i uzyskiwania do nich dostępu za pośrednictwem punktu końcowego w aplikacji.
- Obsługa interfejsów API przekształcania, które umożliwiają modyfikowanie wygenerowanego dokumentu.
- Obsługa generowania wielu dokumentów OpenAPI z jednej aplikacji.
- Korzysta z obsługi schematu JSON udostępnianego przez
System.Text.Json
usługę . - Jest zgodny z natywną usługą AoT.
Instalacja pakietu
Microsoft.AspNetCore.OpenApi
Zainstaluj pakiet:
Uruchom następujące polecenie w konsoli Menedżer pakietów:
Install-Package Microsoft.AspNetCore.OpenApi -IncludePrerelease
Aby dodać obsługę generowania dokumentów OpenAPI w czasie kompilacji, zainstaluj Microsoft.Extensions.ApiDescription.Server
pakiet:
Uruchom następujące polecenie w konsoli Menedżer pakietów:
Install-Package Microsoft.Extensions.ApiDescription.Server -IncludePrerelease
Konfigurowanie generowania dokumentów interfejsu OpenAPI
Następujący kod powoduje:
- Dodaje usługi OpenAPI.
- Włącza punkt końcowy do wyświetlania dokumentu OpenAPI w formacie JSON.
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Uruchom aplikację i przejdź do https://localhost:<port>/openapi/v1.json
strony , aby wyświetlić wygenerowany dokument OpenAPI.
Dołączanie metadanych interfejsu OpenAPI w aplikacji internetowej ASP.NET
Dołączanie metadanych interfejsu OpenAPI dla punktów końcowych
ASP.NET zbiera metadane z punktów końcowych aplikacji internetowej i używa ich do generowania dokumentu OpenAPI.
W aplikacjach opartych na kontrolerach metadane są zbierane z atrybutów, takich jak [EndpointDescription]
, [HttpPost]
i [Produces]
.
W minimalnych interfejsach API metadane mogą być zbierane z atrybutów, ale mogą być również ustawiane przy użyciu metod rozszerzeń i innych strategii, takich jak powrót TypedResults z procedur obsługi tras.
Poniższa tabela zawiera omówienie zebranych metadanych oraz strategii ich ustawiania.
Metadane | Atrybut | Metoda rozszerzenia | Inne strategie |
---|---|---|---|
Podsumowanie | [EndpointSummary] |
WithSummary | |
opis | [EndpointDescription] |
WithDescription | |
tags | [Tags] |
WithTags | |
operationId | [EndpointName] |
WithName | |
parameters | [FromQuery] , , [FromRoute] , , [FromHeader] [FromForm] |
||
opis parametru | [EndpointDescription] |
||
requestBody | [FromBody] |
Accepts | |
Odpowiedzi | [Produces] |
Produces, ProducesProblem | TypedResults |
Wykluczanie punktów końcowych | [ExcludeFromDescription] , [ApiExplorerSettings] |
ExcludeFromDescription |
ASP.NET Core nie zbiera metadanych z komentarzy doc XML.
W poniższych sekcjach przedstawiono sposób dołączania metadanych do aplikacji w celu dostosowania wygenerowanego dokumentu OpenAPI.
Podsumowanie i opis
Podsumowanie i opis punktu końcowego można ustawić przy użyciu [EndpointSummary]
atrybutów i [EndpointDescription]
lub w minimalnych interfejsach API przy użyciu WithSummary metod i WithDescription .
W poniższym przykładzie przedstawiono różne strategie ustawiania podsumowań i opisów.
Należy pamiętać, że atrybuty są umieszczane w metodzie delegata, a nie w aplikacji. Metoda MapGet.
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!");
tags
Interfejs OpenAPI obsługuje określanie tagów dla każdego punktu końcowego jako formy kategoryzacji.
W minimalnych interfejsach API tagi można ustawić przy użyciu atrybutu [Tags]
WithTags lub metody rozszerzenia.
W poniższym przykładzie przedstawiono różne strategie ustawiania tagów.
app.MapGet("/extension-methods", () => "Hello world!")
.WithTags("todos", "projects");
app.MapGet("/attributes",
[Tags("todos", "projects")]
() => "Hello world!");
operationId
Interfejs OpenAPI obsługuje identyfikator operationId dla każdego punktu końcowego jako unikatowy identyfikator lub nazwę operacji.
W minimalnych interfejsach API identyfikator operationId można ustawić przy użyciu atrybutu [EndpointName]
WithName lub metody rozszerzenia.
W poniższym przykładzie przedstawiono różne strategie ustawiania identyfikatora operationId.
app.MapGet("/extension-methods", () => "Hello world!")
.WithName("FromExtensionMethods");
app.MapGet("/attributes",
[EndpointName("FromAttributes")]
() => "Hello world!");
parameters
Interfejs OpenAPI obsługuje dodawanie adnotacji do ścieżki, ciągu zapytania, nagłówka i cookie parametrów używanych przez interfejs API.
Struktura wywnioskuje typy parametrów żądania automatycznie na podstawie podpisu programu obsługi tras.
Atrybut [EndpointDescription]
może służyć do podania opisu parametru.
W poniższym przykładzie pokazano, jak ustawić opis parametru.
app.MapGet("/attributes",
([Description("This is a description.")] string name) => "Hello world!");
Opisz treść żądania
Pole requestBody
w interfejsie OpenAPI opisuje treść żądania, które klient interfejsu API może wysłać do serwera, w tym obsługiwane typy zawartości i schemat zawartości treści.
Gdy metoda obsługi punktu końcowego akceptuje parametry powiązane z treścią żądania, ASP.NET Core generuje odpowiedni requestBody
element dla operacji w dokumencie OpenAPI. Metadane treści żądania można również określić przy użyciu atrybutów lub metod rozszerzenia. Dodatkowe metadane można ustawić za pomocą transformatora dokumentu lub transformatora operacji.
Jeśli punkt końcowy nie definiuje żadnych parametrów powiązanych z treścią żądania, ale używa treści żądania bezpośrednio HttpContext , ASP.NET Core udostępnia mechanizmy określania metadanych treści żądania. Jest to typowy scenariusz dla punktów końcowych, które przetwarzają treść żądania jako strumień.
Niektóre metadane treści żądania można określić na podstawie FromBody
parametrów lub FromForm
metody obsługi tras.
Opis treści żądania można ustawić za pomocą [Description]
atrybutu w parametrze z parametrem FromBody
lub FromForm
.
FromBody
Jeśli parametr jest niepusty i EmptyBodyBehavior nie jest ustawiony na Allow wartość w atrybucieFromBody
, treść żądania jest wymagana, a required
pole obiektu requestBody
jest ustawione na true
wartość w wygenerowanym dokumencie OpenAPI.
Elementy formularza są zawsze wymagane i mają required
ustawioną wartość true
.
Użyj transformatora dokumentu lub transformatora operacji, aby ustawić example
pola , examples
lub encoding
dodać rozszerzenia specyfikacji dla treści żądania w wygenerowanym dokumencie OpenAPI.
Inne mechanizmy ustawiania metadanych treści żądania zależą od typu opracowywanej aplikacji i opisano je w poniższych sekcjach.
Typy zawartości treści żądania w wygenerowanych dokumentach OpenAPI są określane na podstawie typu parametru powiązanego z treścią żądania lub określonego za Accepts pomocą metody rozszerzenia.
Domyślnie typ zawartości parametru FromBody
będzie application/json
mieć wartość , a typ zawartości parametrów FromForm
będzie mieć multipart/form-data
wartość lub application/x-www-form-urlencoded
.
Obsługa tych domyślnych typów zawartości jest wbudowana w interfejsy API minimalne, a inne typy zawartości mogą być obsługiwane za pomocą powiązania niestandardowego. Aby uzyskać więcej informacji, zobacz temat Powiązanie niestandardowe w dokumentacji minimalnych interfejsów API.
Istnieje kilka sposobów określania innego typu zawartości dla treści żądania.
Jeśli typ parametru FromBody
implementuje IEndpointParameterMetadataProviderelement , ASP.NET Core używa tego interfejsu do określania typów zawartości w treści żądania.
Struktura używa PopulateMetadata metody tego interfejsu do ustawiania typów zawartości i typu treści treści żądania. Na przykład klasa, Todo
która akceptuje application/xml
typ zawartości, text/xml
może służyć IEndpointParameterMetadataProvider do przekazywania tych informacji do struktury.
public class Todo : IEndpointParameterMetadataProvider
{
public static void PopulateMetadata(ParameterInfo parameter, EndpointBuilder builder)
{
builder.Metadata.Add(new AcceptsMetadata(["application/xml", "text/xml"], typeof(Todo)));
}
}
Accepts Metodę rozszerzenia można również użyć do określenia typu zawartości treści żądania.
W poniższym przykładzie punkt końcowy akceptuje Todo
obiekt w treści żądania z oczekiwanym typem application/xml
zawartości .
app.MapPut("/todos/{id}", (int id, Todo todo) => ...)
.Accepts<Todo>("application/xml");
Ponieważ application/xml
nie jest wbudowanym typem zawartości, Todo
klasa musi zaimplementować IBindableFromHttpContext<TSelf> interfejs w celu zapewnienia niestandardowego powiązania treści żądania. Na przykład:
public class Todo : IBindableFromHttpContext<Todo>
{
public static async ValueTask<Todo?> BindAsync(HttpContext context, ParameterInfo parameter)
{
var xmlDoc = await XDocument.LoadAsync(context.Request.Body, LoadOptions.None, context.RequestAborted);
var serializer = new XmlSerializer(typeof(Todo));
return (Todo?)serializer.Deserialize(xmlDoc.CreateReader());
}
Jeśli punkt końcowy nie definiuje żadnych parametrów powiązanych z treścią żądania, użyj Accepts metody rozszerzenia, aby określić typ zawartości akceptowany przez punkt końcowy.
Jeśli określisz <wartość AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.Accepts%2A> wiele razy, używane są tylko metadane z ostatniego — nie są one łączone.
Opisywanie typów odpowiedzi
Interfejs OpenAPI obsługuje podawanie opisu odpowiedzi zwracanych z interfejsu API. ASP.NET Core udostępnia kilka strategii ustawiania metadanych odpowiedzi punktu końcowego. Metadane odpowiedzi, które można ustawić, obejmują kod stanu, typ treści odpowiedzi i typy zawartości odpowiedzi. Odpowiedzi w interfejsie OpenAPI mogą zawierać dodatkowe metadane, takie jak opis, nagłówki, linki i przykłady. Te dodatkowe metadane można ustawić za pomocą transformatora dokumentu lub transformatora operacji.
Określone mechanizmy ustawiania metadanych odpowiedzi zależą od typu opracowywanej aplikacji.
W przypadku minimalnych aplikacji interfejsu API ASP.NET Core może wyodrębnić metadane odpowiedzi dodane przez metody rozszerzenia w punkcie końcowym, atrybuty programu obsługi tras i zwracany typ procedury obsługi tras.
- Produces Metodę rozszerzenia można użyć w punkcie końcowym, aby określić kod stanu, typ treści odpowiedzi i typy zawartości odpowiedzi z punktu końcowego.
- Atrybut
[ProducesResponseType]
lub ProducesResponseTypeAttribute<T> może służyć do określania typu treści odpowiedzi. - Program obsługi tras może służyć do zwracania typu implementowania IEndpointMetadataProvider w celu określenia typu i typu zawartości treści odpowiedzi.
- ProducesProblem Metoda rozszerzenia w punkcie końcowym może służyć do określania kodu stanu i typów zawartości odpowiedzi o błędzie.
Należy pamiętać, że Produces metody i ProducesProblem rozszerzenia są obsługiwane zarówno w systemach , jak RouteHandlerBuilder i na RouteGroupBuilder. Dzięki temu można na przykład zdefiniować typowy zestaw odpowiedzi na błędy dla wszystkich operacji w grupie.
Jeśli nie zostanie określona przez jedną z powyższych strategii, następujące elementy:
- Kod stanu odpowiedzi jest domyślnie ustawiony na 200.
- Schemat treści odpowiedzi można wywnioskować z niejawnego lub jawnego typu zwracanego metody punktu końcowego, na przykład z
T
metody w pliku ; w Task<TResult>przeciwnym razie jest uważany za nieokreślony. - Typ zawartości dla określonej lub wnioskowanej treści odpowiedzi to "application/json".
W przypadku minimalnych interfejsów Produces API metoda rozszerzenia i [ProducesResponseType]
atrybut ustawia tylko metadane odpowiedzi dla punktu końcowego. Nie modyfikują ani nie ograniczają zachowania punktu końcowego, który może zwracać inny kod stanu lub typ treści odpowiedzi niż określony przez metadane, a typ zawartości jest określany przez typ zwracany metody obsługi trasy, niezależnie od typu zawartości określonego w atrybutach lub metodach rozszerzeń.
Produces Metoda rozszerzenia może określać typ odpowiedzi punktu końcowego z domyślnym kodem stanu 200 i domyślnym typem application/json
zawartości . Zostało to przedstawione w poniższym przykładzie:
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.Produces<IList<Todo>>();
Element [ProducesResponseType]
może służyć do dodawania metadanych odpowiedzi do punktu końcowego. Należy pamiętać, że atrybut jest stosowany do metody obsługi tras, a nie wywołania metody w celu utworzenia trasy, jak pokazano w poniższym przykładzie:
app.MapGet("/todos",
[ProducesResponseType<List<Todo>>(200)]
async (TodoDb db) => await db.Todos.ToListAsync());
Użycie w TypedResults implementacji programu obsługi tras punktu końcowego automatycznie uwzględnia metadane typu odpowiedzi dla punktu końcowego. Na przykład poniższy kod automatycznie donotuje punkt końcowy z odpowiedzią w 200
kodzie stanu z typem application/json
zawartości.
app.MapGet("/todos", async (TodoDb db) =>
{
var todos = await db.Todos.ToListAsync();
return TypedResults.Ok(todos);
});
Zwracane są tylko typy implementujące IEndpointMetadataProvider tworzenie responses
wpisu w dokumencie OpenAPI. Poniżej znajduje się częściowa lista niektórych TypedResults metod pomocnika, które tworzą responses
wpis:
TypedResults, metoda pomocnika | kod stanu |
---|---|
Ok() | 200 |
Created() | 201 |
CreatedAtRoute() | 201 |
Zaakceptowane() | 202 |
AcceptedAtRoute() | 202 |
NoContent() | 204 |
BadRequest() | 400 |
ValidationProblem() | 400 |
NotFound() | 404 |
Konflikt() | 409 |
UnprocessableEntity() | 422 |
Wszystkie te metody z wyjątkiem NoContent
przeciążenia ogólnego, które określa typ treści odpowiedzi.
Klasę można zaimplementować, aby ustawić metadane punktu końcowego i zwrócić ją z programu obsługi tras.
Ustawianie odpowiedzi dla ProblemDetails
Podczas ustawiania typu odpowiedzi dla punktów końcowych, które mogą zwrócić odpowiedź ProblemDetails, można użyć następującej metody w celu dodania odpowiednich metadanych odpowiedzi dla punktu końcowego:
- ProducesProblem
- ProducesValidationProblem metoda rozszerzenia.
- TypedResults z kodem stanu w zakresie (400-499).
Aby uzyskać więcej informacji na temat konfigurowania minimalnej aplikacji interfejsu API w celu zwrócenia odpowiedzi ProblemDetails, zobacz Obsługa błędów w minimalnych interfejsach API.
Wiele typów odpowiedzi
Jeśli punkt końcowy może zwrócić różne typy odpowiedzi w różnych scenariuszach, możesz podać metadane w następujący sposób:
Wywołaj metodę Produces rozszerzenia wiele razy, jak pokazano w poniższym przykładzie:
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);
Użyj Results<TResult1,TResult2,TResult3,TResult4,TResult5,TResult6> w podpisie i TypedResults w treści programu obsługi, jak pokazano w poniższym przykładzie:
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(); });
Results<TResult1,TResult2,TResultN>
Typy unii deklarują, że procedura obsługi tras zwraca wieleIResult
-implementujących konkretne typy, a każdy z tych typów, które implementująIEndpointMetadataProvider, przyczyni się do metadanych punktu końcowego.Typy unii implementują niejawne operatory rzutowania. Te operatory umożliwiają kompilatorowi automatyczne konwertowanie typów określonych w argumentach ogólnych na wystąpienie typu unii. Ta funkcja ma dodatkową korzyść z zapewnienia sprawdzania czasu kompilacji, że program obsługi tras zwraca tylko wyniki, które deklaruje. Próba zwrócenia typu, który nie jest zadeklarowany jako jeden z argumentów ogólnych, aby spowodować
Results<TResult1,TResult2,TResultN>
błąd kompilacji.
Wykluczanie punktów końcowych z wygenerowanego dokumentu
Domyślnie wszystkie punkty końcowe zdefiniowane w aplikacji są udokumentowane w wygenerowanym pliku OpenAPI, ale punkty końcowe można wykluczyć z dokumentu przy użyciu atrybutów lub metod rozszerzenia.
Mechanizm określania punktu końcowego, który ma zostać wykluczony, zależy od typu opracowywanej aplikacji.
Minimalne interfejsy API obsługują dwie strategie wykluczania danego punktu końcowego z dokumentu OpenAPI:
- ExcludeFromDescription extension, metoda
- Atrybut
[ExcludeFromDescription]
W poniższym przykładzie przedstawiono różne strategie wykluczania danego punktu końcowego z wygenerowanego dokumentu OpenAPI.
app.MapGet("/extension-method", () => "Hello world!")
.ExcludeFromDescription();
app.MapGet("/attributes",
[ExcludeFromDescription]
() => "Hello world!");
Uwzględnianie metadanych interfejsu OpenAPI dla typów danych
Klasy lub rekordy języka C# używane w treści żądania lub odpowiedzi są reprezentowane jako schematy w wygenerowany dokument OpenAPI. Domyślnie tylko właściwości publiczne są reprezentowane w schemacie, ale istnieją JsonSerializerOptions również właściwości schematu dla pól.
PropertyNamingPolicy Gdy właściwość jest ustawiona na camel-case (jest to wartość domyślna w aplikacjach internetowych ASP.NET), nazwy właściwości w schemacie są formą camel-case nazwy właściwości klasy lub rekordu.
Właściwość [JsonPropertyName]
może być używana dla pojedynczej właściwości, aby określić nazwę właściwości w schemacie.
typ i format
Biblioteka schematów JSON mapuje standardowe typy języka C# na interfejs OpenAPI type
i format
w następujący sposób:
Typ języka C# | Interfejs OpenAPI type |
Interfejs OpenAPI format |
---|---|---|
int | integer | int32 |
długi | integer | int64 |
short | integer | int16 |
byte | integer | uint8 |
liczba zmiennoprzecinkowa | Liczba | liczba zmiennoprzecinkowa |
double | Liczba | double |
decimal | Liczba | double |
bool | boolean | |
string | string | |
char | string | char |
byte[] | string | byte |
DateTimeOffset | string | data i godzina |
DateOnly | string | data |
TimeOnly | string | time |
Identyfikator URI | string | uri |
Identyfikator GUID | string | uuid |
obiekt | pominięty | |
dynamiczna | pominięty |
Należy pamiętać, że typy obiektów i typów dynamicznych nie mają zdefiniowanego typu w interfejsie OpenAPI, ponieważ mogą one zawierać dane dowolnego typu, w tym typy pierwotne, takie jak int lub ciąg.
Element type
i format
można również ustawić za pomocą transformatora schematu. Na przykład możesz chcieć format
, aby decimal
typy dziesiętne zamiast double
.
Dodawanie metadanych przy użyciu atrybutów
ASP.NET używa metadanych z atrybutów we właściwościach klasy lub rekordu, aby ustawić metadane we odpowiednich właściwościach wygenerowanego schematu.
Poniższa tabela zawiera podsumowanie atrybutów z System.ComponentModel
przestrzeni nazw, które zapewniają metadane dla wygenerowanego schematu:
Atrybut | opis |
---|---|
[Description] |
description Ustawia właściwość w schemacie. |
[Required] |
Oznacza właściwość tak jak required w schemacie. |
[DefaultValue] |
default Ustawia wartość właściwości w schemacie. |
[Range] |
minimum Ustawia wartość i maximum liczby całkowitej lub liczbowej. |
[MinLength] |
minLength Ustawia wartość ciągu. |
[MaxLength] |
maxLength Ustawia wartość ciągu. |
[RegularExpression] |
pattern Ustawia wartość ciągu. |
Należy pamiętać, że w aplikacjach opartych na kontrolerach te atrybuty dodają filtry do operacji, aby sprawdzić, czy wszystkie dane przychodzące spełniają ograniczenia. W przypadku minimalnych interfejsów API te atrybuty ustawiają metadane w wygenerowanym schemacie, ale walidacja musi być wykonywana jawnie za pośrednictwem filtru punktu końcowego, w logice procedury obsługi tras lub za pośrednictwem pakietu innej firmy.
Inne źródła metadanych dla wygenerowanych schematów
wymagane
Właściwości można również oznaczyć jako required
za pomocą wymaganego modyfikatora.
wyliczenie
Typy wyliczenia w języku C# są oparte na liczbach całkowitych, ale mogą być reprezentowane jako ciągi w formacie JSON z wartością [JsonConverter]
i JsonStringEnumConverter. Gdy typ wyliczenia jest reprezentowany jako ciąg w formacie JSON, wygenerowany schemat będzie miał enum
właściwość z wartościami ciągu wyliczenia.
Typ wyliczenia bez elementu [JsonConverter]
zostanie zdefiniowany tak, jak type: integer
w wygenerowanym schemacie.
Uwaga: Właściwość [AllowedValues]
nie ustawia enum
wartości właściwości.
nullable
Właściwości zdefiniowane jako wartość dopuszczana do wartości null lub typ odwołania mają wartość nullable: true
w wygenerowanym schemacie. Jest to zgodne z domyślnym zachowaniem System.Text.Json deserializacji, który przyjmuje null
jako prawidłową wartość dla właściwości dopuszczanej do wartości null.
additionalProperties
Schematy są domyślnie generowane bez additionalProperties
potwierdzenia, co oznacza wartość domyślną .true
Jest to zgodne z domyślnym zachowaniem System.Text.Json deserializacji, który dyskretnie ignoruje dodatkowe właściwości w obiekcie JSON.
Jeśli dodatkowe właściwości schematu powinny mieć tylko wartości określonego typu, zdefiniuj właściwość lub klasę Dictionary<string, type>
jako . Typ klucza słownika musi mieć wartość string
. Spowoduje to wygenerowanie schematu z additionalProperties
określeniem schematu "type" jako wymaganych typów wartości.
Metadane dla typów polimorficznych
[JsonPolymorphic]
Użyj atrybutów i [JsonDerivedType]
w klasie nadrzędnej, aby określić pola dyskryminujące i podtypy dla typu polimorficznego.
Obiekt [JsonDerivedType]
dodaje pole dyskryminujące do schematu dla każdej podklasy z wyliczeniowym określającym konkretną wartość dyskryminującą dla podklasy. Ten atrybut modyfikuje również konstruktor każdej klasy pochodnej, aby ustawić wartość dyskryminującą.
Klasa abstrakcyjna z atrybutem [JsonPolymorphic]
ma discriminator
pole w schemacie, ale konkretna klasa z atrybutem [JsonPolymorphic]
discriminator
nie ma pola. Interfejs OpenAPI wymaga, aby właściwość dyskryminująca był wymaganą właściwością w schemacie, ale ponieważ właściwość dyskryminująca nie jest zdefiniowana w konkretnej klasie bazowej, schemat nie może zawierać discriminator
pola.
Dodawanie metadanych z transformatorem schematu
Przekształcanie schematu może służyć do zastępowania wszelkich domyślnych metadanych lub dodawania dodatkowych metadanych, takich jak example
wartości, do wygenerowanego schematu. Aby uzyskać więcej informacji, zobacz Używanie transformatorów schematów .
Opcje dostosowywania generowania dokumentów interfejsu OpenAPI
W poniższych sekcjach pokazano, jak dostosować generowanie dokumentów interfejsu OpenAPI.
Dostosowywanie nazwy dokumentu OpenAPI
Każdy dokument OpenAPI w aplikacji ma unikatową nazwę. Domyślna nazwa zarejestrowanego dokumentu to v1
.
builder.Services.AddOpenApi(); // Document name is v1
Nazwę dokumentu można zmodyfikować, przekazując nazwę jako parametr do wywołania AddOpenApi
.
builder.Services.AddOpenApi("internal"); // Document name is internal
Nazwa dokumentu jest wyświetlana w kilku miejscach w implementacji interfejsu OpenAPI.
Podczas pobierania wygenerowanego dokumentu OpenAPI nazwa dokumentu jest podawana jako documentName
argument parametru w żądaniu. Następujące żądania rozpoznają v1
dokumenty i .internal
GET http://localhost:5000/openapi/v1.json
GET http://localhost:5000/openapi/internal.json
Dostosowywanie wersji interfejsu OpenAPI wygenerowanego dokumentu
Domyślnie generowanie dokumentów OpenAPI tworzy dokument zgodny ze specyfikacją interfejsu OpenAPI w wersji 3.0. Poniższy kod pokazuje, jak zmodyfikować domyślną wersję dokumentu OpenAPI:
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi2_0;
});
Dostosowywanie trasy punktu końcowego interfejsu OpenAPI
Domyślnie punkt końcowy interfejsu OpenAPI zarejestrowany za pośrednictwem wywołania MapOpenApi uwidacznia dokument w /openapi/{documentName}.json
punkcie końcowym. Poniższy kod pokazuje, jak dostosować trasę, w której zarejestrowano dokument OpenAPI:
app.MapOpenApi("/openapi/{documentName}/openapi.json");
Możliwe, ale nie jest zalecane, aby usunąć documentName
parametr trasy z trasy punktu końcowego. Po usunięciu parametru documentName
trasy z trasy punktu końcowego struktura próbuje rozpoznać nazwę dokumentu z parametru zapytania. Brak podania documentName
w trasie lub kwerendzie może spowodować nieoczekiwane zachowanie.
Dostosowywanie punktu końcowego interfejsu OpenAPI
Ponieważ dokument OpenAPI jest obsługiwany za pośrednictwem punktu końcowego procedury obsługi tras, wszelkie dostosowania dostępne dla standardowych minimalnych punktów końcowych są dostępne dla punktu końcowego interfejsu OpenAPI.
Ograniczanie dostępu do dokumentów OpenAPI autoryzowanym użytkownikom
Punkt końcowy interfejsu OpenAPI domyślnie nie włącza żadnych testów autoryzacji. Jednak kontrole autoryzacji można zastosować do dokumentu OpenAPI. W poniższym kodzie dostęp do dokumentu OpenAPI jest ograniczony do osób z rolą tester
:
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 wygenerowany w pamięci podręcznej
Dokument OpenAPI jest ponownie wygenerowany przy każdym wysłaniu żądania do punktu końcowego interfejsu OpenAPI. Regeneruj umożliwia przekształcanie w ich działanie dynamicznego stanu aplikacji. Na przykład ponowne generowanie żądania ze szczegółami kontekstu HTTP. Jeśli ma to zastosowanie, dokument OpenAPI można buforować, aby uniknąć wykonywania potoku generowania dokumentów w każdym żądaniu 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();
Przekształcanie dokumentów OpenAPI
W tej sekcji pokazano, jak dostosować dokumenty OpenAPI za pomocą funkcji przekształcania.
Dostosowywanie dokumentów OpenAPI za pomocą funkcji przekształcania
Funkcja Transformers udostępnia interfejs API do modyfikowania dokumentu OpenAPI przy użyciu dostosowań zdefiniowanych przez użytkownika. Transformatory są przydatne w scenariuszach, takich jak:
- Dodawanie parametrów do wszystkich operacji w dokumencie.
- Modyfikowanie opisów parametrów lub operacji.
- Dodawanie informacji najwyższego poziomu do dokumentu OpenAPI.
Transformatory dzielą się na trzy kategorie:
- Transformatory dokumentów mają dostęp do całego dokumentu OpenAPI. Mogą one służyć do wprowadzania globalnych modyfikacji dokumentu.
- Transformatory operacji mają zastosowanie do poszczególnych operacji. Każda pojedyncza operacja jest kombinacją ścieżki i metody HTTP. Mogą one służyć do modyfikowania parametrów lub odpowiedzi w punktach końcowych.
- Transformatory schematu mają zastosowanie do każdego schematu w dokumencie. Mogą one służyć do modyfikowania schematu jednostek żądania lub odpowiedzi lub dowolnych zagnieżdżonych schematów.
Transformatory można zarejestrować w dokumencie, wywołując metodę AddDocumentTransformer OpenApiOptions w obiekcie . Poniższy fragment kodu przedstawia różne sposoby rejestrowania transformatorów w dokumencie:
- Zarejestruj przekształcanie dokumentu przy użyciu delegata.
- Zarejestruj przekształcanie dokumentu przy użyciu wystąpienia IOpenApiDocumentTransformerklasy .
- Zarejestruj przekształcanie dokumentu przy użyciu aktywowanego IOpenApiDocumentTransformerdi.
- Zarejestruj przekształcanie operacji przy użyciu delegata.
- Zarejestruj przekształcanie operacji przy użyciu wystąpienia IOpenApiOperationTransformerklasy .
- Zarejestruj przekształcanie operacji przy użyciu aktywowanego IOpenApiOperationTransformerdi.
- Rejestrowanie transformatora schematu przy użyciu delegata.
- Zarejestruj przekształcanie schematu przy użyciu wystąpienia IOpenApiSchemaTransformerklasy .
- Zarejestruj przekształcanie schematu przy użyciu aktywowanego IOpenApiSchemaTransformerdi.
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();
Kolejność wykonywania transformatorów
Transformatory są wykonywane w pierwszej kolejności na podstawie rejestracji. W poniższym fragmencie kodu transformator dokumentu ma dostęp do modyfikacji wprowadzonych przez transformator operacji:
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();
Korzystanie z funkcji przekształcania dokumentów
Transformatory dokumentów mają dostęp do obiektu kontekstu, który obejmuje:
- Nazwa modyfikowanego dokumentu.
- Skojarzony ApiDescriptionGroups z tym dokumentem.
- Używany IServiceProvider w generowaniu dokumentów.
Transformatory dokumentów mogą również mutować wygenerowany dokument OpenAPI. W poniższym przykładzie pokazano transformator dokumentu, który dodaje pewne informacje o interfejsie 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();
Transformatory dokumentów aktywowanych przez usługę mogą używać wystąpień z di w celu zmodyfikowania aplikacji. W poniższym przykładzie przedstawiono przekształcanie dokumentów, które korzysta z IAuthenticationSchemeProvider usługi z warstwy uwierzytelniania. Sprawdza, czy jakiekolwiek schematy elementu nośnego JWT są zarejestrowane w aplikacji i dodaje je do najwyższego poziomu 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;
}
}
}
Transformatory dokumentów są unikatowe dla wystąpienia dokumentu, z którymi są skojarzone. W poniższym przykładzie transformator:
- Rejestruje wymagania dotyczące uwierzytelniania w dokumencie
internal
. public
Pozostawia dokument niezmodyfikowany.
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>()
});
}
}
}
}
Używanie transformatorów operacji
Operacje to unikatowe kombinacje ścieżek HTTP i metod w dokumencie OpenAPI. Transformatory operacji są przydatne w przypadku modyfikacji:
- Należy wprowadzić do każdego punktu końcowego w aplikacji lub
- Warunkowo stosowane do niektórych tras.
Transformatory operacji mają dostęp do obiektu kontekstu, który zawiera:
- Nazwa dokumentu, do którego należy operacja.
- Skojarzony ApiDescription z operacją.
- Używany IServiceProvider w generowaniu dokumentów.
Na przykład poniższy transformator operacji dodaje 500
jako kod stanu odpowiedzi obsługiwany przez wszystkie operacje w dokumencie.
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();
Korzystanie z transformatorów schematu
Schematy to modele danych używane w jednostkach żądań i odpowiedzi w dokumencie OpenAPI. Transformatory schematu są przydatne w przypadku modyfikacji:
- Należy wykonać do każdego schematu w dokumencie lub
- Warunkowo stosowane do niektórych schematów.
Transformatory schematu mają dostęp do obiektu kontekstu, który zawiera:
- Nazwa dokumentu, do którego należy schemat.
- Informacje o typie JSON skojarzone ze schematem docelowym.
- Używany IServiceProvider w generowaniu dokumentów.
Na przykład następujące przekształcanie schematu ustawia format
typy dziesiętne na decimal
wartość zamiast 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; }
}
Dodatkowe zasoby
Minimalne interfejsy API zapewniają wbudowaną obsługę generowania informacji o punktach końcowych w aplikacji za pośrednictwem Microsoft.AspNetCore.OpenApi
pakietu. Uwidacznianie wygenerowanej definicji interfejsu OpenAPI za pomocą wizualnego interfejsu użytkownika wymaga pakietu innej firmy. Aby uzyskać informacje o obsłudze interfejsu OpenAPI w interfejsach API opartych na kontrolerach, zobacz wersję tego artykułu platformy .NET 9.
Poniższy kod jest generowany przez szablon interfejsu API internetowego ASP.NET Core i używa interfejsu 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);
}
W poprzednim wyróżnionym kodzie:
Microsoft.AspNetCore.OpenApi
objaśniono w następnej sekcji.- AddEndpointsApiExplorer : konfiguruje aplikację tak, aby używała Eksploratora interfejsów API do odnajdywania i opisywania punktów końcowych z domyślnymi adnotacjami.
WithOpenApi
zastępuje pasujące, domyślne adnotacje wygenerowane przez Eksploratora interfejsów API z utworzonymi zMicrosoft.AspNetCore.OpenApi
pakietu. UseSwagger
dodaje oprogramowanie pośredniczące struktury Swagger.- Element "UseSwaggerUI" umożliwia osadzoną wersję narzędzia Swagger UI.
- WithName: Element IEndpointNameMetadata w punkcie końcowym jest używany do generowania linków i jest traktowany jako identyfikator operacji w specyfikacji OpenAPI danego punktu końcowego.
WithOpenApi
w dalszej części tego artykułu wyjaśniono.
Microsoft.AspNetCore.OpenApi
Pakiet NuGet
ASP.NET Core udostępnia pakiet do interakcji ze specyfikacjami interfejsu Microsoft.AspNetCore.OpenApi
OpenAPI dla punktów końcowych. Pakiet działa jako link między modelami OpenAPI zdefiniowanymi w pakiecie i punktami końcowymi zdefiniowanymi w Microsoft.AspNetCore.OpenApi
minimalnych interfejsach API. Pakiet udostępnia interfejs API, który analizuje parametry, odpowiedzi i metadane punktu końcowego w celu konstruowania typu adnotacji interfejsu OpenAPI używanego do opisywania punktu końcowego.
Microsoft.AspNetCore.OpenApi
element jest dodawany jako element PackageReference do pliku 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>
W przypadku używania z Microsoft.AspNetCore.OpenApi
programem należy użyć Swashbuckle.AspNetCore
programu w Swashbuckle.AspNetCore
wersji 6.4.0 lub nowszej. Microsoft.OpenApi
1.4.3 lub nowsza musi być używana do użycia konstruktorów kopii w WithOpenApi
wywołaniach.
Dodawanie adnotacji interfejsu OpenAPI do punktów końcowych za pomocą polecenia WithOpenApi
Wywołanie metody WithOpenApi
w punkcie końcowym dodaje do metadanych punktu końcowego. Te metadane mogą być następujące:
- Używane w pakietach innych firm, takich jak Swashbuckle.AspNetCore.
- Wyświetlane w interfejsie użytkownika struktury Swagger lub w formacie YAML lub JSON wygenerowano w celu zdefiniowania interfejsu 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();
Modyfikowanie adnotacji interfejsu OpenAPI w pliku WithOpenApi
Metoda WithOpenApi
akceptuje funkcję, która może służyć do modyfikowania adnotacji interfejsu OpenAPI. Na przykład w poniższym kodzie opis jest dodawany do pierwszego parametru punktu końcowego:
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;
});
Dodawanie identyfikatorów operacji do interfejsu OpenAPI
Identyfikatory operacji służą do unikatowego identyfikowania danego punktu końcowego w interfejsie OpenAPI. Metodę WithName
rozszerzenia można użyć do ustawienia identyfikatora operacji używanego dla metody.
app.MapGet("/todoitems2", async (TodoDb db) =>
await db.Todos.ToListAsync())
.WithName("GetToDoItems");
Alternatywnie OperationId
właściwość można ustawić bezpośrednio w adnotacji OpenAPI.
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.WithOpenApi(operation => new(operation)
{
OperationId = "GetTodos"
});
Dodawanie tagów do opisu interfejsu OpenAPI
Interfejs OpenAPI obsługuje kategoryzowanie operacji przy użyciu obiektów tagów . Te tagi są zwykle używane do grupowania operacji w interfejsie użytkownika struktury Swagger. Te tagi można dodać do operacji, wywołując metodę rozszerzenia WithTags w punkcie końcowym z żądanymi tagami.
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync())
.WithTags("TodoGroup");
Alternatywnie można ustawić listę adnotacji OpenApiTags
OpenAPI za pomocą WithOpenApi
metody rozszerzenia.
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.WithOpenApi(operation => new(operation)
{
Tags = new List<OpenApiTag> { new() { Name = "Todos" } }
});
Dodawanie podsumowania lub opisu punktu końcowego
Podsumowanie i opis punktu końcowego można dodać, wywołując metodę WithOpenApi
rozszerzenia. W poniższym kodzie podsumowania są ustawiane bezpośrednio w adnotacji interfejsu 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"
});
Wyklucz opis interfejsu OpenAPI
W poniższym przykładzie /skipme
punkt końcowy jest wykluczony z generowania opisu interfejsu 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();
Oznaczanie interfejsu API jako przestarzałego
Aby oznaczyć punkt końcowy jako przestarzały, ustaw Deprecated
właściwość w adnotacji interfejsu OpenAPI.
app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.WithOpenApi(operation => new(operation)
{
Deprecated = true
});
Opisywanie typów odpowiedzi
Interfejs OpenAPI obsługuje podawanie opisu odpowiedzi zwracanych z interfejsu API. Minimalne interfejsy API obsługują trzy strategie ustawiania typu odpowiedzi punktu końcowego:
Produces
Za pośrednictwem metody rozszerzenia w punkcie końcowym- Za pośrednictwem atrybutu
ProducesResponseType
w procedurze obsługi tras - Wracając
TypedResults
z programu obsługi tras
Metoda Produces
rozszerzenia może służyć do dodawania Produces
metadanych do punktu końcowego. Jeśli nie podano parametrów, metoda rozszerzenia wypełnia metadane dla docelowego typu w 200
kodzie stanu i application/json
typie zawartości.
app
.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
.Produces<IList<Todo>>();
Użycie w TypedResults
implementacji programu obsługi tras punktu końcowego automatycznie uwzględnia metadane typu odpowiedzi dla punktu końcowego. Na przykład poniższy kod automatycznie donotuje punkt końcowy z odpowiedzią w 200
kodzie stanu z typem application/json
zawartości.
app.MapGet("/todos", async (TodoDb db) =>
{
var todos = await db.Todos.ToListAsync());
return TypedResults.Ok(todos);
});
Ustawianie odpowiedzi dla ProblemDetails
Podczas ustawiania typu odpowiedzi dla punktów końcowych, które mogą zwrócić odpowiedź ProblemDetails, ProducesProblem metoda ProducesValidationProblemrozszerzenia , lub TypedResults.Problem
może służyć do dodawania odpowiedniej adnotacji do metadanych punktu końcowego. Należy pamiętać, że ProducesProblem
metody i ProducesValidationProblem
rozszerzenia nie mogą być używane z grupami tras na platformie .NET 8 i starszych wersjach.
Jeśli nie ma jawnych adnotacji dostarczonych przez jedną z powyższych strategii, struktura próbuje określić domyślny typ odpowiedzi, sprawdzając podpis odpowiedzi. Ta domyślna odpowiedź jest wypełniana w kodzie stanu w definicji interfejsu 200
OpenAPI.
Wiele typów odpowiedzi
Jeśli punkt końcowy może zwrócić różne typy odpowiedzi w różnych scenariuszach, możesz podać metadane w następujący sposób:
Wywołaj metodę
Produces
rozszerzenia wiele razy, jak pokazano w poniższym przykładzie: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);
Użyj
Results<TResult1,TResult2,TResultN>
w podpisie iTypedResults
w treści programu obsługi, jak pokazano w poniższym przykładzie: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(); });
Results<TResult1,TResult2,TResultN>
Typy unii deklarują, że procedura obsługi tras zwraca wieleIResult
-implementujących konkretne typy, a każdy z tych typów, które implementująIEndpointMetadataProvider
, przyczyni się do metadanych punktu końcowego.Typy unii implementują niejawne operatory rzutowania. Te operatory umożliwiają kompilatorowi automatyczne konwertowanie typów określonych w argumentach ogólnych na wystąpienie typu unii. Ta funkcja ma dodatkową korzyść z zapewnienia sprawdzania czasu kompilacji, że program obsługi tras zwraca tylko wyniki, które deklaruje. Próba zwrócenia typu, który nie jest zadeklarowany jako jeden z argumentów ogólnych, aby spowodować
Results<TResult1,TResult2,TResultN>
błąd kompilacji.
Opisywanie treści i parametrów żądania
Oprócz opisywania typów zwracanych przez punkt końcowy interfejs OpenAPI obsługuje również dodawanie adnotacji do danych wejściowych używanych przez interfejs API. Te dane wejściowe należą do dwóch kategorii:
- Parametry wyświetlane w ścieżce, ciągu zapytania, nagłówkach lub plikach cookie
- Dane przesyłane w ramach treści żądania
Struktura automatycznie wnioskuje typy parametrów żądania w ścieżce, zapytaniu i ciągu nagłówka na podstawie podpisu procedury obsługi tras.
Aby zdefiniować typ danych wejściowych przesyłanych jako treść żądania, skonfiguruj właściwości przy użyciu Accepts
metody rozszerzenia w celu zdefiniowania typu obiektu i typu zawartości oczekiwanego przez procedurę obsługi żądań. W poniższym przykładzie punkt końcowy akceptuje Todo
obiekt w treści żądania z oczekiwanym typem application/xml
zawartości .
app.MapPost("/todos/{id}", (int id, Todo todo) => ...)
.Accepts<Todo>("application/xml");
Oprócz metody rozszerzenia typ parametru Accepts
może opisywać własną adnotację przez zaimplementowanie interfejsu IEndpointParameterMetadataProvider
. Na przykład następujący Todo
typ dodaje adnotację, która wymaga treści żądania z typem application/xml
zawartości.
public class Todo : IEndpointParameterMetadataProvider
{
public static void PopulateMetadata(ParameterInfo parameter, EndpointBuilder builder)
{
builder.Metadata.Add(new ConsumesAttribute(typeof(Todo), isOptional: false, "application/xml"));
}
}
Jeśli nie podano jawnej adnotacji, platforma próbuje określić domyślny typ żądania, jeśli w procedurze obsługi punktu końcowego istnieje parametr treści żądania. Wnioskowanie używa następujących heurystyki do utworzenia adnotacji:
- Parametry treści żądania odczytywane z formularza za pośrednictwem atrybutu
[FromForm]
multipart/form-data
są opisane przy użyciu typu zawartości. - Wszystkie inne parametry treści żądania są opisane przy użyciu
application/json
typu zawartości. - Treść żądania jest traktowana jako opcjonalna, jeśli jest dopuszczana wartość null lub właściwość
AllowEmpty
jest ustawiona na atrybucieFromBody
.
Obsługa wersji interfejsu API
Minimalne interfejsy API obsługują przechowywanie wersji interfejsu API za pośrednictwem pakietu Asp.Versioning.Http. Przykłady konfigurowania wersji przy użyciu minimalnych interfejsów API można znaleźć w repozytorium przechowywania wersji interfejsu API.
kod źródłowy interfejsu OpenAPI platformy ASP.NET Core w witrynie GitHub
Dodatkowe zasoby
Minimalna aplikacja interfejsu API może opisać specyfikację interfejsu OpenAPI dla procedur obsługi tras przy użyciu pakietu Swashbuckle.
Aby uzyskać informacje o obsłudze interfejsu OpenAPI w interfejsach API opartych na kontrolerach, zobacz wersję tego artykułu platformy .NET 9.
Poniższy kod to typowa aplikacja ASP.NET Core z obsługą interfejsu 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();
Wyklucz opis interfejsu OpenAPI
W poniższym przykładzie /skipme
punkt końcowy jest wykluczony z generowania opisu interfejsu 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();
Opisywanie typów odpowiedzi
W poniższym przykładzie użyto wbudowanych typów wyników, aby dostosować odpowiedź:
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);
Dodawanie identyfikatorów operacji do interfejsu OpenAPI
app.MapGet("/todoitems2", async (TodoDb db) =>
await db.Todos.ToListAsync())
.WithName("GetToDoItems");
Dodawanie tagów do opisu interfejsu OpenAPI
Poniższy kod używa tagu grupowania interfejsu OpenAPI:
app.MapGet("/todoitems", async (TodoDb db) =>
await db.Todos.ToListAsync())
.WithTags("TodoGroup");