Minimal API アプリでの OpenAPI のサポート
OpenAPI 仕様は、HTTP API を文書化するためのプログラミング言語に依存しない標準です。 この標準は、Minimal API では、組み込みの API とオープンソース ライブラリの組み合わせによりサポートされます。 アプリケーションでの OpenAPI 統合には、次の 3 つの重要な側面があります。
- アプリ内のエンドポイントに関する情報を生成します。
- OpenAPI スキーマに一致する形式で情報を収集します。
- 生成された OpenAPI スキーマをビジュアル UI またはシリアル化されたファイルを通して公開します。
Minimal API は、Microsoft.AspNetCore.OpenApi
パッケージを使ってアプリ内のエンドポイントに関する情報を生成するための組み込みサポートを提供します。 生成された OpenAPI 定義をビジュアル UI で表示するには、サードパーティ製のパッケージが必要です。
次のコードは、ASP.NET Core の最小限の Web 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 Explorer を使用して、既定の注釈によってエンドポイントを検出して記述するようにアプリを構成します。
WithOpenApi
は、一致する、API Explorer によって生成された既定の注釈を、Microsoft.AspNetCore.OpenApi
パッケージから生成された注釈でオーバーライドします。 UseSwagger
は Swagger ミドルウェアを追加します。UseSwaggerUI
では、開発モードで Swagger UI ツールの埋め込みバージョンが有効になります。- WithName: エンドポイントの IEndpointNameMetadata はリンク生成に使用され、指定されたエンドポイントの OpenAPI 仕様の操作 ID として扱われます。
WithOpenApi
については、この記事で後ほど説明します。
Microsoft.AspNetCore.OpenApi
NuGet パッケージ
ASP.NET Core では、エンドポイントの OpenAPI 仕様と対話するための Microsoft.AspNetCore.OpenApi
パッケージが提供されます。 このパッケージは、Microsoft.AspNetCore.OpenApi
パッケージで定義されている OpenAPI モデルと、Minimal 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
拡張メソッドを使って、OpenApiTags
の一覧を OpenAPI 注釈に設定することもできます。
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 の記述を除外する
次のサンプルでは、OpenAPI の説明の生成から /skipme
エンドポイントが除外されます。
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 から返される応答の記述を提供できます。 Minimal API は、エンドポイントの応答の型を設定するための 3 つの方法をサポートしています。
- エンドポイント上の
Produces
拡張メソッドによる方法 - ルート ハンドラーの
ProducesResponseType
属性を使う方法 - ルート ハンドラーから
TypedResults
を返す方法
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
を実装するこれらのいずれの型がエンドポイントのメタデータに寄与することを宣言します。共用体型は、暗黙的なキャスト演算子を実装します。 これらの演算子により、コンパイラはジェネリック引数で指定されている型を共用体型のインスタンスに自動的に変換できるようになります。 この機能にはさらに、ルート ハンドラーからそうすることが宣言されている結果のみが返されることがコンパイル時にチェックされるという利点があります。 ジェネリック引数の 1 つとして宣言されていない型を
Results<TResult1,TResult2,TResultN>
に返そうとすると、コンパイル エラーが発生します。
要求本文とパラメーターについて記述する
OpenAPI では、エンドポイントによって返される型を記述するだけでなく、API によって使用される入力に注釈を付けることもできます。 これらの入力は、2 つのカテゴリに分類されます。
- パス、クエリ文字列、ヘッダー、または 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 バージョン管理のサポート
Minimal API では、Asp.Versioning.Http パッケージを使った API バージョン管理をサポートしています。 Minimal API でバージョン管理を構成する例については、API バージョン管理リポジトリを参照してください。
GitHub 上の ASP.NET Core OpenAPI ソース コード
その他のリソース
OpenAPI 仕様は、HTTP API を文書化するためのプログラミング言語に依存しない標準です。 この標準は、Minimal API では、組み込みの API とオープンソース ライブラリの組み合わせによりサポートされます。 アプリケーションでの OpenAPI 統合には、次の 3 つの重要な側面があります。
- アプリ内のエンドポイントに関する情報を生成します。
- OpenAPI スキーマに一致する形式で情報を収集します。
- 生成された OpenAPI スキーマをビジュアル UI またはシリアル化されたファイルを通して公開します。
Minimal API は、Microsoft.AspNetCore.OpenApi
パッケージを使ってアプリ内のエンドポイントに関する情報を生成するための組み込みサポートを提供します。 生成された OpenAPI 定義をビジュアル UI で表示するには、サードパーティ製のパッケージが必要です。
次のコードは、ASP.NET Core の最小限の Web 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 Explorer を使用して、既定の注釈によってエンドポイントを検出して記述するようにアプリを構成します。
WithOpenApi
は、一致する、API Explorer によって生成された既定の注釈を、Microsoft.AspNetCore.OpenApi
パッケージから生成された注釈でオーバーライドします。 UseSwagger
は Swagger ミドルウェアを追加します。- `UseSwaggerUI` により、Swagger UI ツールの埋め込みバージョンが有効になります。
- WithName: エンドポイントの IEndpointNameMetadata はリンク生成に使用され、指定されたエンドポイントの OpenAPI 仕様の操作 ID として扱われます。
WithOpenApi
については、この記事で後ほど説明します。
Microsoft.AspNetCore.OpenApi
NuGet パッケージ
ASP.NET Core では、エンドポイントの OpenAPI 仕様と対話するための Microsoft.AspNetCore.OpenApi
パッケージが提供されます。 このパッケージは、Microsoft.AspNetCore.OpenApi
パッケージで定義されている OpenAPI モデルと、Minimal 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
拡張メソッドを使って、OpenApiTags
の一覧を OpenAPI 注釈に設定することもできます。
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 の記述を除外する
次のサンプルでは、OpenAPI の説明の生成から /skipme
エンドポイントが除外されます。
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 から返される応答の記述を提供できます。 Minimal API は、エンドポイントの応答の型を設定するための 3 つの方法をサポートしています。
- エンドポイント上の
Produces
拡張メソッドによる方法 - ルート ハンドラーの
ProducesResponseType
属性を使う方法 - ルート ハンドラーから
TypedResults
を返す方法
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
を実装するこれらのいずれの型がエンドポイントのメタデータに寄与することを宣言します。共用体型は、暗黙的なキャスト演算子を実装します。 これらの演算子により、コンパイラはジェネリック引数で指定されている型を共用体型のインスタンスに自動的に変換できるようになります。 この機能にはさらに、ルート ハンドラーからそうすることが宣言されている結果のみが返されることがコンパイル時にチェックされるという利点があります。 ジェネリック引数の 1 つとして宣言されていない型を
Results<TResult1,TResult2,TResultN>
に返そうとすると、コンパイル エラーが発生します。
要求本文とパラメーターについて記述する
OpenAPI では、エンドポイントによって返される型を記述するだけでなく、API によって使用される入力に注釈を付けることもできます。 これらの入力は、2 つのカテゴリに分類されます。
- パス、クエリ文字列、ヘッダー、または 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 バージョン管理のサポート
Minimal API では、Asp.Versioning.Http パッケージを使った API バージョン管理をサポートしています。 Minimal 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 の記述を除外する
次のサンプルでは、OpenAPI の説明の生成から /skipme
エンドポイントが除外されます。
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");
ASP.NET Core
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示