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 typu "transformer", które pozwalają na modyfikację wygenerowanego dokumentu.
  • Obsługa generowania wielu dokumentów OpenAPI z jednej aplikacji.
  • Korzysta z obsługi schematu JSON udostępnianego przez System.Text.Json.
  • Jest zgodny z natywną funkcją AoT.

Instalacja pakietu

Microsoft.AspNetCore.OpenApi Zainstaluj pakiet:

Uruchom następujące polecenie w konsoli Menedżer pakietów:

Install-Package Microsoft.AspNetCore.OpenApi

Konfigurowanie generowania dokumentów interfejsu OpenAPI

Następujący kod:

  • Dodaje usługi OpenAPI przy użyciu metody rozszerzenia AddOpenApi w kolekcji usług konstruktora aplikacji.
  • Mapuje punkt końcowy do wyświetlania dokumentu OpenAPI w formacie JSON za pomocą metody rozszerzenia MapOpenApi w aplikacji.
var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    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.

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 rozstrzygają dokumenty v1 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;
});

Dostosuj ścieżkę punktu końcowego interfejsu OpenAPI

Domyślnie punkt końcowy interfejsu OpenAPI zarejestrowany za pośrednictwem wywołania MapOpenApi uwidacznia dokument w punkcie końcowym /openapi/{documentName}.json. 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 usunięcie parametru trasy documentName z trasy końcowej. Po usunięciu parametru documentName z ścieżki punktu końcowego, platforma próbuje rozpoznać nazwę dokumentu z parametru zapytania. Brak podania documentName w ścieżce lub kwerendzie może spowodować nieprzewidziane zachowanie.

Dostosowywanie punktu końcowego interfejsu OpenAPI

Ponieważ dokument OpenAPI jest obsługiwany za pośrednictwem punktu końcowego obsługującego trasę, wszystkie dostosowania dostępne dla standardowych minimalnych punktów końcowych są dostępne także 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. Regeneracja umożliwia transformatorom inkorporowanie dynamicznego stanu aplikacji do ich działania. 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 dokumentu dla każdego żądania 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();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi()
        .CacheOutput();
}

app.MapGet("/", () => "Hello world!");

app.Run();

Generowanie wielu dokumentów OpenAPI

W niektórych scenariuszach pomocne jest wygenerowanie wielu dokumentów OpenAPI o różnej zawartości z jednej aplikacji API ASP.NET Core. Scenariusze obejmują:

  • Generowanie dokumentacji OpenAPI zarówno dla publicznych, jak i wewnętrznych API.
  • Generowanie dokumentacji interfejsu OpenAPI dla różnych wersji interfejsu API.
  • Generowanie dokumentacji interfejsu OpenAPI dla różnych części aplikacji, takich jak interfejs API frontonu i zaplecza.

Aby wygenerować wiele dokumentów OpenAPI, wywołaj metodę rozszerzenia AddOpenApi raz dla każdego dokumentu, określając inną nazwę dokumentu w pierwszym parametrze za każdym razem.

builder.Services.AddOpenApi("v1");
builder.Services.AddOpenApi("v2");

Każde wywołanie AddOpenApi może określać własny zestaw opcji, dzięki czemu można użyć tych samych lub różnych dostosowań dla każdego dokumentu OpenAPI.

Struktura używa metody delegata ShouldIncludeOpenApiOptions, aby określić, które punkty końcowe mają być uwzględnione w każdym dokumencie.

Dla każdego dokumentu metoda delegata ShouldInclude jest wywoływana dla każdego punktu końcowego w aplikacji, przekazując obiekt ApiDescription dla punktu końcowego. Metoda zwraca wartość logiczną wskazującą, czy punkt końcowy powinien zostać uwzględniony w dokumencie. Obiekt ApiDescription:

  • zawiera informacje o punkcie końcowym, takie jak metoda HTTP, trasa i typy odpowiedzi
  • Metadane dołączone do punktu końcowego za pomocą atrybutów lub metod rozszerzenia.

Domyślna implementacja tego delegata używa pola GroupNameApiDescription. Delegat jest definiowany w punkcie końcowym za pomocą metody rozszerzenia WithGroupName lub atrybutu EndpointGroupNameAttribute. WithGroupName lub atrybut EndpointGroupName określa, które punkty końcowe mają być uwzględnione w dokumencie. Każdy punkt końcowy, który nie został przypisany do nazwy grupy, jest uwzględniony we wszystkich dokumentach OpenAPI.

    // Include endpoints without a group name or with a group name that matches the document name
    ShouldInclude = (description) => description.GroupName == null || description.GroupName == DocumentName;    

Możesz dostosować metodę delegata ShouldInclude, aby uwzględnić lub wykluczyć punkty końcowe na podstawie dowolnych kryteriów.

Generowanie dokumentów OpenAPI w czasie kompilacji

W typowych aplikacjach internetowych dokumenty OpenAPI są generowane w czasie wykonywania i obsługiwane za pośrednictwem żądania HTTP do serwera aplikacji.

W niektórych scenariuszach warto wygenerować dokument OpenAPI podczas kroku kompilacji aplikacji. Scenariusze obejmują:

  • Generowanie dokumentacji interfejsu OpenAPI zatwierdzonej w systemie kontroli wersji.
  • Generowanie dokumentacji interfejsu OpenAPI używanej do testowania integracji opartego na specyfikacji.
  • Generowanie dokumentacji interfejsu OpenAPI obsługiwanej statycznie z serwera internetowego.

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

Po zainstalowaniu tego pakietu:

  • Automatycznie generuje dokumenty open API skojarzone z aplikacją podczas kompilacji.
  • Umieszcza dokumenty Open API w katalogu wyjściowym aplikacji.

Jeśli zarejestrowano wiele dokumentów, i nazwa dokumentu nie jest v1, jest dołączona na końcu z nazwą dokumentu. Np. {ProjectName}_{DocumentName}.json.

dotnet build
type obj\{ProjectName}.json

Dostosowywanie generowania dokumentu w czasie kompilacji

Modyfikowanie katalogu wyjściowego wygenerowanego pliku open API

Domyślnie wygenerowany dokument OpenAPI będzie emitowany do katalogu wyjściowego aplikacji. Aby zmodyfikować lokalizację emitowanego pliku, ustaw ścieżkę docelową OpenApiDocumentsDirectory we właściwości .

<PropertyGroup>
  <OpenApiDocumentsDirectory>.</OpenApiDocumentsDirectory>
</PropertyGroup>

Wartość parametru OpenApiDocumentsDirectory jest ustalana względem pliku projektu. Użycie powyższej . wartości spowoduje emitowanie dokumentu OpenAPI w tym samym katalogu co plik projektu.

Modyfikowanie nazwy pliku wyjściowego

Domyślnie wygenerowany dokument OpenAPI będzie miał taką samą nazwę jak plik projektu aplikacji. Aby zmodyfikować nazwę emitowanego pliku, ustaw --file-name parametr w OpenApiGenerateDocumentsOptions właściwości.

<PropertyGroup>
  <OpenApiGenerateDocumentsOptions>--file-name my-open-api</OpenApiGenerateDocumentsOptions>
</PropertyGroup>

Wybieranie dokumentu OpenAPI do wygenerowania

Niektóre aplikacje można skonfigurować do emitowania wielu dokumentów OpenAPI. Dla różnych wersji interfejsu API można wygenerować wiele dokumentów OpenAPI lub rozróżniać publiczne i wewnętrzne interfejsy API. Domyślnie generator dokumentów w czasie kompilacji emituje pliki dla wszystkich dokumentów skonfigurowanych w aplikacji. Aby wyprowadzać wynik tylko dla pojedynczej nazwy dokumentu, ustaw argument --document-name we właściwości OpenApiGenerateDocumentsOptions.

<PropertyGroup>
  <OpenApiGenerateDocumentsOptions>--document-name v2</OpenApiGenerateDocumentsOptions>
</PropertyGroup>

Dostosowywanie zachowania czasu wykonywania podczas generowania dokumentu w czasie kompilacji

Funkcje generowania dokumentów OpenAPI na etapie budowania przez uruchomienie punktu startowego aplikacji z implementacją symulowanego serwera. Do utworzenia dokładnych dokumentów OpenAPI wymagany jest pozorowany serwer, ponieważ nie można statycznie analizować wszystkich informacji w dokumencie OpenAPI. Ponieważ wywoływany jest punkt wejścia aplikacji, wywoływana jest dowolna logika podczas uruchamiania aplikacji. Obejmuje to kod, który wprowadza usługi do kontenera DI lub odczytuje z konfiguracji. W niektórych scenariuszach należy ograniczyć ścieżki kodu, które będą uruchamiane, kiedy punkt wejścia aplikacji jest wywoływany podczas generowania dokumentów w czasie kompilacji. Scenariusze obejmują:

  • Brak odczytu z niektórych ciągów konfiguracji.
  • Nie rejestruje usług związanych z bazą danych.

Aby ograniczyć wywoływanie tych ścieżek kodu przez mechanizm generowania w czasie kompilacji, można je warunkować sprawdzaniem zestawu początkowego:

using System.Reflection;

var builder = WebApplication.CreateBuilder(args);

if (Assembly.GetEntryAssembly()?.GetName().Name != "GetDocument.Insider")
{
    builder.AddServiceDefaults();
}

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
}

var myKeyValue = app.Configuration["MyKey"];

app.MapGet("/", () => {
    return Results.Ok($"The value of MyKey is: {myKeyValue}");
})
.WithName("TestKey");

app.Run();

AddServiceDefaults dodaje typowe usługi .NET Aspire, takie jak odnajdywanie usług, odporność, kontrole kondycji i openTelemetry.

Przycinanie i natywne kompilowanie AOT

Interfejs OpenAPI w programie ASP.NET Core obsługuje przycinanie i natywną funkcję AOT. Poniższe kroki umożliwiają utworzenie i opublikowanie aplikacji OpenAPI z przycinaniem i natywną funkcją AOT:

Utwórz nowy projekt ASP.NET Core Web API (Native AOT).

dotnet new webapiaot

Dodaj pakiet Microsoft.AspNetCore.OpenAPI.

dotnet add package Microsoft.AspNetCore.OpenApi

Zaktualizuj Program.cs, aby umożliwić generowanie dokumentów OpenAPI.

+ builder.Services.AddOpenApi();

var app = builder.Build();

+ app.MapOpenApi();

Opublikuj aplikację.

dotnet publish

Minimalne API zapewniają wbudowaną obsługę generowania informacji o punktach końcowych w aplikacji za pośrednictwem pakietu Microsoft.AspNetCore.OpenApi. Udostępnienie wygenerowanej definicji OpenAPI za pomocą wizualnego interfejsu wymaga zewnętrznego pakietu. 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 minimalnego API internetowego ASP.NET Core i używa 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 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.
  • Wyjaśnienie WithOpenApi zostanie przedstawione w dalszej części tego artykułu.

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>

Podczas korzystania z Swashbuckle.AspNetCore z Microsoft.AspNetCore.OpenApi, należy użyć Swashbuckle.AspNetCore w 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.

Dodaj adnotacje OpenAPI do punktów końcowych za pomocą WithOpenApi

Wywołanie WithOpenApi na punkcie końcowym dodaje informacje do jego metadanych. Te metadane mogą być następujące:

  • Używane w pakietach innych firm, takich jak Swashbuckle.AspNetCore.
  • Wyświetlane w interfejsie użytkownika Swagger lub wygenerowanym w formacie YAML lub JSON 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();

Zmodyfikuj adnotację OpenAPI w 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, można ustawić właściwość OperationId 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 oznaczenia są zwykle używane do grupowania operacji w interfejsie Swagger UI. 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, listę OpenApiTags można ustawić w adnotacji OpenAPI za pomocą metody rozszerzenia WithOpenApi.

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ę rozszerzenia WithOpenApi. W poniższym kodzie podsumowania są ustawiane bezpośrednio w adnotacji 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 właściwość Deprecated w adnotacji 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 uzupełnia metadane dla typu docelowego przy użyciu kodu stanu 200 i typu zawartości application/json.

app
    .MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .Produces<IList<Todo>>();

Użycie TypedResults w implementacji trasy punktu końcowego automatycznie uwzględnia metadane dotyczące typu odpowiedzi dla tego punktu. Na przykład, poniższy kod automatycznie oznacza punkt końcowy, przypisując do niego odpowiedź dla 200 kodu stanu o typie zawartości application/json.

app.MapGet("/todos", async (TodoDb db) =>
{
    var todos = await db.Todos.ToListAsync());
    return TypedResults.Ok(todos);
});

Ustaw odpowiedzi dla ProblemDetails

Podczas ustawiania typu odpowiedzi dla punktów końcowych, które mogą zwrócić odpowiedź ProblemDetails, metoda rozszerzenia ProducesProblem, ProducesValidationProblem lub TypedResults.Problem może być używana do dodania odpowiedniej adnotacji do metadanych punktu końcowego. Należy pamiętać, że metody rozszerzające ProducesProblem i ProducesValidationProblem 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 przypisana do kodu stanu 200 w definicji 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 zjednoczenia deklarują, że procedura obsługi trasy zwraca wiele konkretnych typów implementujących IResult, a każdy z tych typów, który implementuje 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 możliwość ma dodatkową korzyść, ponieważ umożliwia sprawdzanie w czasie kompilacji, że program obsługi tras zwraca tylko te wyniki, które deklaruje. Próba zwrócenia typu, który nie jest zadeklarowany jako jeden z argumentów ogólnych, powoduje Results<TResult1,TResult2,TResultN> błąd kompilacji.

Opisywanie treści i parametrów żądania

Oprócz opisywania typów zwracanych przez punkt końcowy, OpenAPI obsługuje również adnotowanie danych wejściowych przetwarzanych 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

Framework automatycznie wnioskuje typy parametrów żądania w ścieżce, zapytaniu i ciągu nagłówka na podstawie sygnatury obsługującego 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 obiekt Todo w treści żądania z oczekiwanym typem zawartości application/xml.

app.MapPost("/todos/{id}", (int id, Todo todo) => ...)
  .Accepts<Todo>("application/xml");

Oprócz stosowania metody rozszerzenia Accepts typ parametru może opisywać własną adnotację poprzez implementację 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

Interfejsy API typu minimalnego obsługują wersjonowanie API przez pakiet Asp.Versioning.Http. Przykłady konfigurowania wersjonowania przy użyciu minimalnych interfejsów API można znaleźć w repozytorium wersjonowania API.

kod źródłowy interfejsu OpenAPI platformy ASP.NET Core w witrynie GitHub

Dodatkowe zasoby

Minimalna aplikacja API może opisać specyfikację OpenAPI dla obsługi tras przy użyciu 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 punkt końcowy /skipme jest wykluczony z generowania opisu 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 OpenAPI:

app.MapGet("/todoitems", async (TodoDb db) =>
    await db.Todos.ToListAsync())
    .WithTags("TodoGroup");