Udostępnij za pośrednictwem


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.Jsonusł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ć examplepola , exampleslub 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/xmlzawartoś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/jsonzawartoś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:

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 wiele IResult-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:

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:

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:

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:

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 z Microsoft.AspNetCore.OpenApi pakietu.
  • UseSwaggerdodaje 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.OpenApiprogramem 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:

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 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 wiele IResult-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/xmlzawartoś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 atrybucie FromBody .

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");