최소 API 앱에서 OpenAPI 지원

OpenAPI 사양은 HTTP API를 문서화하기 위한 프로그래밍 언어 독립적 표준입니다. 이 표준은 기본 제공 API와 오픈 소스 라이브러리의 조합을 통해 최소 API에서 지원됩니다. 애플리케이션에서 OpenAPI 통합에는 다음과 같은 세 가지 주요 측면이 있습니다.

  • 앱의 엔드포인트에 대한 정보 생성.
  • OpenAPI 스키마와 일치하는 형식으로 정보 수집.
  • 시각적 UI 또는 직렬화된 파일을 통해 생성된 OpenAPI 스키마 노출.

최소 API는 Microsoft.AspNetCore.OpenApi 패키지를 통해 앱의 엔드포인트에 대한 정보를 생성하기 위한 기본 제공 지원을 제공합니다. 시각적 UI를 통해 생성된 OpenAPI 정의를 노출하려면 타사 패키지가 필요합니다.

다음 코드는 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 패키지에서 생성된 주석으로 재정의합니다.
  • UseSwaggerSwagger 미들웨어를 추가합니다. nuget 패키지가 Swashbuckle.AspNetCore 필요합니다.
  • UseSwaggerUI 는 개발 모드에서 Swagger UI 도구의 포함된 버전을 사용하도록 설정합니다.
  • WithName: 엔드포인트의 IEndpointNameMetadata는 링크 생성에 사용되며 지정된 엔드포인트의 OpenAPI 사양에서 작업 ID로 처리됩니다.
  • WithOpenApi는 이 문서 뒷부분에 설명되어 있습니다.

Microsoft.AspNetCore.OpenApi NuGet 패키지

ASP.NET Core는 엔드포인트에 대한 OpenAPI 사양과 상호 작용하는 Microsoft.AspNetCore.OpenApi 패키지를 제공합니다. 이 패키지는 Microsoft.AspNetCore.OpenApi 패키지에 정의된 OpenAPI 모델과 최소 API에 정의된 엔드포인트 간의 링크 역할을 합니다. 이 패키지는 엔드포인트의 매개 변수, 응답 및 메타데이터를 검사하여 엔드포인트를 설명하는 데 사용되는 OpenAPI 주석 형식을 생성하는 API를 제공합니다.

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>

Microsoft.AspNetCore.OpenApi, Swashbuckle.AspNetCore와 함께 Swashbuckle.AspNetCore를 사용할 때 6.4.0 이상을 사용해야 합니다. WithOpenApi 호출에서 복사 생성자를 활용하려면 Microsoft.OpenApi 1.4.3 이상을 사용해야 합니다.

WithOpenApi를 통해 엔드포인트에 OpenAPI 주석 추가

엔드포인트에서 WithOpenApi를 호출하면 엔드포인트의 메타데이터가 추가됩니다. 이 메타데이터는 다음과 같습니다.

  • Swashbuckle.AspNetCore와 같은 타사 패키지에서 사용합니다.
  • Swagger 사용자 인터페이스 또는 API을 정의하기 위해 생성된 YAML 또는 JSON에 표시됩니다.
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();

WithOpenApi에서 OpenAPI 주석 수정

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에 작업 ID 추가

작업 ID는 OpenAPI에서 지정된 엔드포인트를 고유하게 식별하는 데 사용됩니다. WithName 확장 메서드를 사용하여 메서드에 사용되는 작업 ID를 설정할 수 있습니다.

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

또는 OpenAPI 주석에서 직접 OperationId 속성을 설정할 수 있습니다.

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

OpenAPI 설명에 태그 추가

OpenAPI는 태그 개체 를 사용하여 작업을 분류할 수 있도록 지원합니다. 이러한 태그는 일반적으로 Swagger UI에서 작업을 그룹화하는 데 사용됩니다. 이러한 태그는 원하는 태그를 사용하여 엔드포인트에서 WithTags 확장 메서드를 호출하여 작업에 추가할 수 있습니다.

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

또는 WithOpenApi 확장 메서드를 통해 OpenAPI 주석에서 OpenApiTags 목록을 설정할 수 있습니다.

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를 사용되지 않는 것으로 표시

엔드포인트를 사용되지 않는 것으로 표시하려면 OpenAPI 주석에서 Deprecated 속성을 설정합니다.

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

응답 형식 설명

OpenAPI는 API에서 반환된 응답에 대한 설명을 제공할 수 있습니다. 최소 API는 엔드포인트의 응답 유형을 설정하기 위한 세 가지 전략을 지원합니다.

Produces 확장 메서드를 사용하여 엔드포인트에 Produces 메타데이터를 추가할 수 있습니다. 매개 변수가 제공되지 않으면 확장 메서드는 200 상태 코드 및 application/json 콘텐츠 형식에서 대상 형식에 대한 메타데이터를 채웁니다.

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

엔드포인트의 경로 처리기 구현에서 TypedResults를 사용하면 엔드포인트에 대한 응답 형식 메타데이터가 자동으로 포함됩니다. 예를 들어, 다음 코드는 application/json 콘텐츠 형식의 200 상태 코드 아래에 응답으로 엔드포인트에 자동으로 주석을 추가합니다.

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

ProblemDetails에 대한 응답 설정

ProblemDetails 응답을 반환할 수 있는 엔드포인트에 대한 응답 유형을 설정할 때, ProducesProblem 확장 메서드 또는 TypedResults.Problem를 엔드포인트의 메타데이터에 적절한 주석을 추가하는 데 사용할 수 있습니다.

위의 전략 중 하나에서 제공하는 명시적 주석이 없는 경우, 프레임워크는 응답의 서명을 검사하여 기본 응답 유형을 확인하려고 시도합니다. 이 기본 응답은 OpenAPI 정의의 200 상태 코드 아래에 채워집니다.

여러 응답 유형

엔드포인트가 다양한 시나리오에서 다른 응답 형식을 반환할 수 있는 경우 다음과 같은 방법으로 메타데이터를 제공할 수 있습니다.

  • 다음 예제와 같이 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 확장 메서드를 사용하여 요청 처리기에서 예상하는 개체 형식 및 콘텐츠 형식을 정의하여 속성을 구성합니다. 다음 예제에서 엔드포인트는 요청 본문에 예상되는 콘텐츠 형식이 application/xmlTodo 개체를 허용합니다.

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 콘텐츠 형식으로 설명됩니다.
  • 요청 본문은 nullable이거나 AllowEmpty 속성이 FromBody 특성에 설정된 경우 선택 사항으로 처리됩니다.

API 버전 관리 지원

최소 API는 Asp.Versioning.Http 패키지를 통해 API 버전 관리를 지원합니다. 최소 API를 사용하여 버전 관리를 구성하는 예제는 API 버전 관리 리포지토리에서 찾을 수 있습니다.

GitHub의 ASP.NET Core OpenAPI 소스 코드

추가 리소스

OpenAPI 사양은 HTTP API를 문서화하기 위한 프로그래밍 언어 독립적 표준입니다. 이 표준은 기본 제공 API와 오픈 소스 라이브러리의 조합을 통해 최소 API에서 지원됩니다. 애플리케이션에서 OpenAPI 통합에는 다음과 같은 세 가지 주요 측면이 있습니다.

  • 앱의 엔드포인트에 대한 정보 생성.
  • OpenAPI 스키마와 일치하는 형식으로 정보 수집.
  • 시각적 UI 또는 직렬화된 파일을 통해 생성된 OpenAPI 스키마 노출.

최소 API는 Microsoft.AspNetCore.OpenApi 패키지를 통해 앱의 엔드포인트에 대한 정보를 생성하기 위한 기본 제공 지원을 제공합니다. 시각적 UI를 통해 생성된 OpenAPI 정의를 노출하려면 타사 패키지가 필요합니다.

다음 코드는 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 패키지에서 생성된 주석으로 재정의합니다.
  • UseSwaggerSwagger 미들웨어를 추가합니다.
  • 'UseSwaggerUI'를 사용하면 포함된 버전의 Swagger UI 도구를 사용할 수 있습니다.
  • WithName: 엔드포인트의 IEndpointNameMetadata는 링크 생성에 사용되며 지정된 엔드포인트의 OpenAPI 사양에서 작업 ID로 처리됩니다.
  • WithOpenApi는 이 문서 뒷부분에 설명되어 있습니다.

Microsoft.AspNetCore.OpenApi NuGet 패키지

ASP.NET Core는 엔드포인트에 대한 OpenAPI 사양과 상호 작용하는 Microsoft.AspNetCore.OpenApi 패키지를 제공합니다. 이 패키지는 Microsoft.AspNetCore.OpenApi 패키지에 정의된 OpenAPI 모델과 최소 API에 정의된 엔드포인트 간의 링크 역할을 합니다. 이 패키지는 엔드포인트의 매개 변수, 응답 및 메타데이터를 검사하여 엔드포인트를 설명하는 데 사용되는 OpenAPI 주석 형식을 생성하는 API를 제공합니다.

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>

Microsoft.AspNetCore.OpenApi, Swashbuckle.AspNetCore와 함께 Swashbuckle.AspNetCore를 사용할 때 6.4.0 이상을 사용해야 합니다. WithOpenApi 호출에서 복사 생성자를 활용하려면 Microsoft.OpenApi 1.4.3 이상을 사용해야 합니다.

WithOpenApi를 통해 엔드포인트에 OpenAPI 주석 추가

엔드포인트에서 WithOpenApi를 호출하면 엔드포인트의 메타데이터가 추가됩니다. 이 메타데이터는 다음과 같습니다.

  • Swashbuckle.AspNetCore와 같은 타사 패키지에서 사용합니다.
  • Swagger 사용자 인터페이스 또는 API을 정의하기 위해 생성된 YAML 또는 JSON에 표시됩니다.
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();

WithOpenApi에서 OpenAPI 주석 수정

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에 작업 ID 추가

작업 ID는 OpenAPI에서 지정된 엔드포인트를 고유하게 식별하는 데 사용됩니다. WithName 확장 메서드를 사용하여 메서드에 사용되는 작업 ID를 설정할 수 있습니다.

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

또는 OpenAPI 주석에서 직접 OperationId 속성을 설정할 수 있습니다.

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

OpenAPI 설명에 태그 추가

OpenAPI는 태그 개체 를 사용하여 작업을 분류할 수 있도록 지원합니다. 이러한 태그는 일반적으로 Swagger UI에서 작업을 그룹화하는 데 사용됩니다. 이러한 태그는 원하는 태그를 사용하여 엔드포인트에서 WithTags 확장 메서드를 호출하여 작업에 추가할 수 있습니다.

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

또는 WithOpenApi 확장 메서드를 통해 OpenAPI 주석에서 OpenApiTags 목록을 설정할 수 있습니다.

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를 사용되지 않는 것으로 표시

엔드포인트를 사용되지 않는 것으로 표시하려면 OpenAPI 주석에서 Deprecated 속성을 설정합니다.

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

응답 형식 설명

OpenAPI는 API에서 반환된 응답에 대한 설명을 제공할 수 있습니다. 최소 API는 엔드포인트의 응답 유형을 설정하기 위한 세 가지 전략을 지원합니다.

Produces 확장 메서드를 사용하여 엔드포인트에 Produces 메타데이터를 추가할 수 있습니다. 매개 변수가 제공되지 않으면 확장 메서드는 200 상태 코드 및 application/json 콘텐츠 형식에서 대상 형식에 대한 메타데이터를 채웁니다.

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

엔드포인트의 경로 처리기 구현에서 TypedResults를 사용하면 엔드포인트에 대한 응답 형식 메타데이터가 자동으로 포함됩니다. 예를 들어, 다음 코드는 application/json 콘텐츠 형식의 200 상태 코드 아래에 응답으로 엔드포인트에 자동으로 주석을 추가합니다.

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

ProblemDetails에 대한 응답 설정

ProblemDetails 응답을 반환할 수 있는 엔드포인트에 대한 응답 유형을 설정할 때, ProducesProblem 확장 메서드 또는 TypedResults.Problem를 엔드포인트의 메타데이터에 적절한 주석을 추가하는 데 사용할 수 있습니다.

위의 전략 중 하나에서 제공하는 명시적 주석이 없는 경우, 프레임워크는 응답의 서명을 검사하여 기본 응답 유형을 확인하려고 시도합니다. 이 기본 응답은 OpenAPI 정의의 200 상태 코드 아래에 채워집니다.

여러 응답 유형

엔드포인트가 다양한 시나리오에서 다른 응답 형식을 반환할 수 있는 경우 다음과 같은 방법으로 메타데이터를 제공할 수 있습니다.

  • 다음 예제와 같이 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 확장 메서드를 사용하여 요청 처리기에서 예상하는 개체 형식 및 콘텐츠 형식을 정의하여 속성을 구성합니다. 다음 예제에서 엔드포인트는 요청 본문에 예상되는 콘텐츠 형식이 application/xmlTodo 개체를 허용합니다.

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 콘텐츠 형식으로 설명됩니다.
  • 요청 본문은 nullable이거나 AllowEmpty 속성이 FromBody 특성에 설정된 경우 선택 사항으로 처리됩니다.

API 버전 관리 지원

최소 API는 Asp.Versioning.Http 패키지를 통해 API 버전 관리를 지원합니다. 최소 API를 사용하여 버전 관리를 구성하는 예제는 API 버전 관리 리포지토리에서 찾을 수 있습니다.

GitHub의 ASP.NET Core OpenAPI 소스 코드

추가 리소스

앱은 Swashbuckle을 사용하여 경로 처리기의 OpenAPI 사양을 설명할 수 있습니다.

다음 코드는 OpenAPI를 지원하는 일반적인 ASP.NET Core 앱입니다.

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에 작업 ID 추가

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