Поделиться через


Создание документов OpenAPI

Пакет Microsoft.AspNetCore.OpenApi обеспечивает встроенную поддержку создания документов OpenAPI в ASP.NET Core. Пакет предоставляет следующие функции:

  • Поддержка создания документов OpenAPI во время выполнения и доступа к ним через конечную точку приложения.
  • Поддержка API-интерфейсов "преобразователя", позволяющих изменять созданный документ.
  • Поддержка создания нескольких документов OpenAPI из одного приложения.
  • Использует преимущества поддержки схемы JSON, предоставляемой System.Text.Json.
  • Совместим с собственным AoT.

Установка пакета

Установите пакет Microsoft.AspNetCore.OpenApi.

Выполните следующую команду из консоли диспетчер пакетов:

Install-Package Microsoft.AspNetCore.OpenApi

Настройка создания документов OpenAPI

Следующий код:

  • Добавляет службы OpenAPI с помощью метода расширения AddOpenApi в коллекции служб построителя приложений.
  • Назначает конечную точку для просмотра документа OpenAPI в формате JSON с помощью метода расширения MapOpenApi в приложении.
var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

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

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

app.Run();

Запустите приложение и перейдите к https://localhost:<port>/openapi/v1.json, чтобы просмотреть созданный документ OpenAPI.

Параметры настройки создания документов OpenAPI

В следующих разделах показано, как настроить создание документов OpenAPI.

Настройка имени документа OpenAPI

Каждый документ OpenAPI в приложении имеет уникальное имя. Имя документа по умолчанию, которое регистрируется, это v1.

builder.Services.AddOpenApi(); // Document name is v1

Имя документа можно изменить, передав имя в качестве параметра вызову AddOpenApi .

builder.Services.AddOpenApi("internal"); // Document name is internal

Имя документа отображается в нескольких местах в реализации OpenAPI.

При получении созданного документа OpenAPI имя документа указывается в качестве documentName аргумента параметра в запросе. Следующие запросы разрешают документы v1 и internal.

GET http://localhost:5000/openapi/v1.json
GET http://localhost:5000/openapi/internal.json

Настройка версии OpenAPI созданного документа

По умолчанию, генерация документов OpenAPI создает документ, соответствующий спецификации OpenAPI версии 3.0. В следующем коде показано, как изменить версию документа OpenAPI по умолчанию:

builder.Services.AddOpenApi(options =>
{
    options.OpenApiVersion = OpenApiSpecVersion.OpenApi2_0;
});

Настройка маршрута конечной точки OpenAPI

По умолчанию конечная точка OpenAPI, зарегистрированная через вызов MapOpenApi, предоставляет доступ к документу на конечной точке /openapi/{documentName}.json. В следующем коде показано, как настроить маршрут, в котором зарегистрирован документ OpenAPI:

app.MapOpenApi("/openapi/{documentName}/openapi.json");

Возможно, но не рекомендуется удалить documentName параметр маршрута из маршрута конечной точки. При удалении параметра маршрута из маршрута конечной точки фреймворк пытается определить имя документа на основе параметра запроса. Не предоставляя documentName ни в маршруте, ни в запросе, можно столкнуться с непредвиденным поведением.

Настройка конечной точки OpenAPI

Так как документ OpenAPI обслуживается через конечную точку обработчика маршрутов, любая настройка, доступная для стандартных минимальных конечных точек, доступна для конечной точки OpenAPI.

Ограничение доступа к документам OpenAPI авторизованным пользователям

Конечная точка OpenAPI не включает проверки авторизации по умолчанию. Однако проверки авторизации можно применить к документу OpenAPI. В следующем коде доступ к документу OpenAPI ограничен тем, кто имеет 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();

Созданный в кэше документ OpenAPI

Документ OpenAPI создается каждый раз, когда отправляется запрос к конечной точке OpenAPI. Восстановление позволяет преобразователям включать динамическое состояние приложения в свою работу. Например, повторное создание запроса с подробными сведениями о контексте HTTP. При необходимости документ OpenAPI можно кэшировать, чтобы избежать выполнения конвейера создания документов для каждого 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();

Создание нескольких документов OpenAPI

В некоторых сценариях полезно создать несколько документов OpenAPI с разным содержимым из одного приложения API ASP.NET Core. Ниже приведены соответствующие сценарии.

  • Создание документации OpenAPI для разных аудиторий, таких как общедоступные и внутренние API.
  • Генерация документации OpenAPI для различных версий API.
  • Создание документации OpenAPI для различных частей приложения, таких как интерфейсный и внутренний API.

Чтобы создать несколько документов OpenAPI, вызовите метод расширения AddOpenApi один раз для каждого документа, указав другое имя документа в первом параметре каждый раз.

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

Каждый вызов AddOpenApi может указать собственный набор параметров, чтобы можно было использовать одинаковые или разные настройки для каждого документа OpenAPI.

Фреймворк использует метод делегата ShouldInclude от OpenApiOptions, чтобы определить, какие конечные точки включить в каждый документ.

Для каждого документа метод делегата ShouldInclude вызывается для каждой конечной точки в приложении, передавая объект ApiDescription для этой конечной точки. Метод возвращает логическое значение, указывающее, должна ли конечная точка быть включена в документ. Объект ApiDescription:

  • содержит сведения о конечной точке, например метод HTTP, маршрут и типы ответов.
  • Метаданные, подключенные к конечной точке с помощью атрибутов или методов расширения.

Реализация этого делегата по умолчанию использует поле GroupName из ApiDescription. Делегат задается на конечной точке с помощью метода расширения WithGroupName или атрибута EndpointGroupNameAttribute. WithGroupName или атрибут EndpointGroupName определяет, какие конечные точки следует включить в документ. Любая конечная точка, которой не было назначено имя группы, включена во все документы 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;    

Вы можете настроить метод делегата ShouldInclude для включения или исключения конечных точек на основе любого выбранного критерия.

Создание документов OpenAPI во время сборки

В типичных веб-приложениях документы OpenAPI создаются во время выполнения и обслуживаются через HTTP-запрос на сервер приложений.

В некоторых сценариях полезно создать документ OpenAPI на этапе сборки приложения. Ниже приведены соответствующие сценарии.

  • Создание документации OpenAPI, закоммиченной в систему контроля версий.
  • Создание документации по OpenAPI, используемой для тестирования интеграции на основе спецификаций.
  • Создание документации OpenAPI, которая обслуживается статическим образом с веб-сервера.

Чтобы добавить поддержку создания документов OpenAPI во время сборки, установите Microsoft.Extensions.ApiDescription.Server пакет:

Выполните следующую команду из консоли диспетчер пакетов:

Install-Package Microsoft.Extensions.ApiDescription.Server

После установки этот пакет:

  • Автоматически создает документы Open API, связанные с приложением во время сборки.
  • Заполняет документы Open API в выходном каталоге приложения.

Если зарегистрировано несколько документов, и имя документа неv1, оно исправлено с именем документа. Пример: {ProjectName}_{DocumentName}.json.

dotnet build
type obj\{ProjectName}.json

Настройка создания документов во время сборки

Изменение выходного каталога созданного файла Open API

По умолчанию созданный документ OpenAPI будет выведен в выходной каталог приложения. Чтобы изменить расположение генерируемого файла, задайте целевой путь в свойстве OpenApiDocumentsDirectory .

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

Значение OpenApiDocumentsDirectory определяется относительно файла проекта. Используя приведенное . выше значение, документ OpenAPI будет выдаваться в том же каталоге, что и файл проекта.

Изменение имени выходного файла

По умолчанию созданный документ OpenAPI будет иметь то же имя, что и файл проекта приложения. Чтобы изменить имя сгенерированного файла, задайте аргумент --file-name в свойстве OpenApiGenerateDocumentsOptions.

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

Выбор документа OpenAPI для генерации

Некоторые приложения могут быть настроены для выдачи нескольких документов OpenAPI. Несколько документов OpenAPI могут создаваться для разных версий API или различать общедоступные и внутренние API. По умолчанию генератор документов во время сборки выдает файлы для всех документов, настроенных в приложении. Чтобы выполнять действия только для одного имени документа, задайте аргумент --document-name в свойстве OpenApiGenerateDocumentsOptions.

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

Настройка поведения программы в процессе генерации документа во время сборки

Функции генерации документации OpenAPI во время сборки, осуществляемые запуском точки входа приложения с использованием имитации сервера. Сервер макета требуется для создания точных документов OpenAPI, так как все сведения в документе OpenAPI не могут быть статически проанализированы. Так как вызывается точка входа приложений, вызывается любая логика запуска приложений. Сюда входит код, который внедряет службы в контейнер DI или считывает данные из конфигурации. В некоторых сценариях необходимо ограничить ветви кода, которые будут выполняться при вызове точки входа приложений во время генерации документов на этапе сборки. Ниже приведены соответствующие сценарии.

  • Не считывается из определенных строк конфигурации.
  • Не регистрируя службы, связанные с базами данных.

Чтобы ограничить доступ к этим путям кода со стороны потока генерации во время сборки, их использование можно условно ограничить проверкой входной сборки.

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 добавляет общие службы .NET Aspire, такие как диспетчеризация служб, отказоустойчивость, мониторинг состояния и OpenTelemetry.

Обрезка и нативный AOT

OpenAPI в ASP.NET Core поддерживает обрезку и собственный AOT. Следующие шаги по созданию и публикации приложения OpenAPI с обрезкой и собственным AOT:

Создайте проект ASP.NET Core Web API (Native AOT).

dotnet new webapiaot

Добавьте пакет Microsoft.AspNetCore.OpenAPI.

dotnet add package Microsoft.AspNetCore.OpenApi

Обновите Program.cs, чтобы включить создание документов OpenAPI.

+ builder.Services.AddOpenApi();

var app = builder.Build();

+ app.MapOpenApi();

Опубликуйте приложение.

dotnet publish

Минимальные API обеспечивают встроенную поддержку создания сведений о конечных точках в приложении с помощью Microsoft.AspNetCore.OpenApi пакета. Для предоставления созданного определения OpenAPI через визуальный пользовательский интерфейс требуется сторонний пакет. Сведения о поддержке OpenAPI в API на основе контроллеров см. в версии .NET 9 этой статьи.

Следующий код создается шаблоном ASP.NET Core для минимального веб-API и использует стандарт 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);
}

В предыдущем выделенном коде:

  • Microsoft.AspNetCore.OpenApi рассматривается в следующем разделе;
  • AddEndpointsApiExplorer настраивает приложение для использования обозревателя API для обнаружения и описания конечных точек с аннотациями по умолчанию. WithOpenApi переопределяет соответствующие аннотации по умолчанию, созданные обозревателем API, на те, что созданы из пакета Microsoft.AspNetCore.OpenApi.
  • UseSwagger добавляет промежуточное ПО Swagger.
  • UseSwaggerUI включает встроенную версию средства пользовательского интерфейса Swagger.
  • WithName означает, что IEndpointNameMetadata для конечной точки используется для создания ссылок и рассматривается как идентификатор операции в спецификации OpenAPI для конкретной конечной точки;
  • WithOpenApi объясняется далее в этой статье.

пакет NuGet Microsoft.AspNetCore.OpenApi;

ASP.NET Core предоставляет пакет Microsoft.AspNetCore.OpenApi для взаимодействия со спецификациями OpenAPI для конечных точек. Этот пакет создает связь между моделями OpenAPI, определенными в пакете Microsoft.AspNetCore.OpenApi, и конечными точками, определенными в минимальных API. Этот пакет предоставляет API, который проверяет параметры, ответы и метаданные конечной точки и создает тип заметки OpenAPI, подходящий для описания этой конечной точки.

Microsoft.AspNetCore.OpenApi добавляется в проект в формате PackageReference (ссылка на пакет):

<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>

При использовании Swashbuckle.AspNetCore совместно с Microsoft.AspNetCore.OpenApi необходимо использовать Swashbuckle.AspNetCore версии 6.4.0 или более поздней. Microsoft.OpenApi Для использования конструкторов копирования в WithOpenApi вызовах необходимо использовать 1.4.3 или более поздней версии.

Добавьте аннотации OpenAPI к конечным точкам с помощью WithOpenApi

Вызов WithOpenApi добавляет информацию в метаданные конечной точки. Эти метаданные могут быть:

  • Используются в сторонних пакетах, например Swashbuckle.AspNetCore.
  • Отображается в пользовательском интерфейсе Swagger или в YAML или JSON, созданном для определения 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();

Измените аннотацию OpenAPI в WithOpenApi

Метод WithOpenApi принимает функцию, которую можно использовать для изменения заметки OpenAPI. Например, следующий код добавляет описание в первый параметр конечной точки:

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

Добавление идентификаторов операций в OpenAPI

Идентификаторы операций используются для уникальной идентификации заданной конечной точки в OpenAPI. WithName Метод расширения можно использовать для задания идентификатора операции, используемого для метода.

app.MapGet("/todoitems2", async (TodoDb db) =>
    await db.Todos.ToListAsync())
    .WithName("GetToDoItems");

Кроме того, OperationId свойство можно задать непосредственно в заметке OpenAPI.

app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .WithOpenApi(operation => new(operation)
    {
        OperationId = "GetTodos"
    });

Добавление тегов в описание OpenAPI

OpenAPI поддерживает использование объектов тегов для классификации операций. Эти теги обычно используются для группирования операций в пользовательском интерфейсе Swagger. Эти теги можно добавить в операцию, вызвав метод расширения WithTags в конечной точке с нужными тегами.

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

В качестве альтернативы, список OpenApiTags можно задать в аннотации OpenAPI посредством метода расширения WithOpenApi.

app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .WithOpenApi(operation => new(operation)
    {
        Tags = new List<OpenApiTag> { new() { Name = "Todos" } }
    });

Добавление сводки или описания конечной точки

Сводку и описание данных конечной WithOpenApi точки можно добавить, вызвав метод расширения. В следующем коде сводки задаются непосредственно в заметке 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"
    });

Исключение описания OpenAPI

В следующем примере конечная точка /skipme исключается из создания описания 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();

Пометить API как устаревший

Чтобы пометить конечную точку как устаревшую, задайте Deprecated свойство в заметке OpenAPI.

app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .WithOpenApi(operation => new(operation)
    {
        Deprecated = true
    });

Описание типов ответов

OpenAPI поддерживает описание ответов, возвращаемых API. Минимальные API поддерживают три стратегии настройки типа ответа конечной точки:

  • С помощью метода расширения Produces на конечной точке
  • С помощью атрибута ProducesResponseType в обработчике маршрутов
  • Возврат TypedResults из обработчика маршрутов

Produces Метод расширения можно использовать для добавления Produces метаданных в конечную точку. Если параметры отсутствуют, метод расширения заполняет метаданные целевого типа в коде 200 состояния и application/json типе контента.

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

Использование TypedResults в реализации обработчика маршрутов конечной точки автоматически включает метаданные типа ответа для конечной точки. Например, следующий код автоматически аннотирует конечную точку с ответом под кодом состояния 200 с типом содержимого application/json.

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

Настройка ответов для ProblemDetails

При настройке типа ответа для конечных точек, которые могут возвращать ответ ProblemDetails, метод расширения ProducesProblem, ProducesValidationProblem или TypedResults.Problem можно использовать для добавления соответствующей аннотации в метаданные конечной точки. Обратите внимание, что методы расширения ProducesProblem и ProducesValidationProblem нельзя использовать с группами маршрутов в .NET 8 и предыдущих версиях.

Если нет явных заметок, предоставляемых одной из описанных выше стратегий, платформа пытается определить тип ответа по умолчанию, проверив подпись ответа. Ответ по умолчанию указывается под кодом состояния 200 в определении OpenAPI.

Несколько типов ответов

Если конечная точка может возвращать различные типы ответов в разных сценариях, можно предоставить метаданные следующим образом:

  • Вызовите метод расширения Produces несколько раз, как показано в следующем примере:

    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);
    
  • Используйте Results<TResult1,TResult2,TResultN> в сигнатуре и TypedResults в тексте обработчика, как показано в следующем примере.

    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> Объединенные типы объявляют, что обработчик маршрутов возвращает несколько конкретных типов, реализующих IResult, и любой из этих типов, который реализует IEndpointMetadataProvider, будет добавлять информацию в метаданные конечной точки.

    Типы объединения реализуют неявные операторы приведения. Эти операторы позволяют компилятору автоматически преобразовывать типы, указанные в универсальных аргументах, в экземпляр типа объединения. Эта возможность обладает дополнительным преимуществом в виде проверки на этапе компиляции, которая гарантирует, что обработчик маршрутов возвращает только те результаты, которые он заявляет. Попытка вернуть тип, который не заявлен явно как один из универсальных аргументов Results<TResult1,TResult2,TResultN>, приводит к ошибке компиляции.

Описание текста запроса и параметров

Помимо описания типов, возвращаемых конечной точкой, OpenAPI также поддерживает аннотирование входных данных, используемых API. Эти входные данные делятся на две категории:

  • Параметры, отображаемые в пути, строке запроса, заголовках или файлах cookie
  • Данные, передаваемые как часть текста запроса

Платформа определяет типы параметров запроса в пути, запросе и строке заголовка автоматически на основе подписи обработчика маршрутов.

Чтобы определить тип входных данных, передаваемых в виде текста запроса, настройте свойства с помощью Accepts метода расширения для определения типа объекта и типа контента, ожидаемого обработчиком запроса. В следующем примере конечная точка принимает Todo объект в тексте запроса с ожидаемым типом application/xmlконтента.

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

Помимо метода расширения Accepts, тип параметра может описать собственную аннотацию, реализуя IEndpointParameterMetadataProvider интерфейсом. Например, следующий Todo тип добавляет заметку, требующую тело запроса с контент-типом application/xml.

public class Todo : IEndpointParameterMetadataProvider
{
    public static void PopulateMetadata(ParameterInfo parameter, EndpointBuilder builder)
    {
        builder.Metadata.Add(new ConsumesAttribute(typeof(Todo), isOptional: false, "application/xml"));
    }
}

Если нет явной аннотации, фреймворк пытается определить стандартный тип запроса, если в обработчике конечной точки есть параметр тела запроса. Вывод использует следующие эвристики для создания заметки:

  • Параметры текста запроса, которые считываются из формы с помощью атрибута [FromForm] , описываются с типом multipart/form-data контента.
  • Все остальные параметры тела запроса описаны с типом содержимого application/json.
  • Тело запроса рассматривается как необязательное, если его значение - null или если свойство AllowEmpty задано для атрибута FromBody.

Поддержка управления версиями API

Минимальные API поддерживают управление версиями API с помощью пакета Asp.Versioning.Http. Примеры настройки управления версиями с минимальными API можно найти в репозитории управления версиями API.

Исходный код OpenAPI ASP.NET Core на GitHub

Дополнительные ресурсы

Упрощённое приложение API может описать спецификацию OpenAPI для обработчиков маршрутов с помощью Swashbuckle.

Сведения о поддержке OpenAPI в API на основе контроллеров см. в версии .NET 9 этой статьи.

Следующий код является типичным приложением ASP.NET Core с поддержкой 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();

Исключение описания OpenAPI

В следующем примере конечная точка /skipme исключается из создания описания 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();

Описание типов ответов

В следующем примере для настройки ответа используются встроенные типы результатов:

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

Добавление идентификаторов операций в OpenAPI

app.MapGet("/todoitems2", async (TodoDb db) =>
    await db.Todos.ToListAsync())
    .WithName("GetToDoItems");

Добавление тегов в описание OpenAPI

В следующем коде используется тег группирования OpenAPI:

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