はじめに
近年、C#でWeb APIを実装する方法として注目されているのがMinimal APIです。
これはASP.NET Coreに追加された新機能で、従来のControllerを使わずにエンドポイントを記述できます。
コード量は非常に少ない一方で、ASP.NETの豊富な機能(ミドルウェア、認証、DIなど)はそのまま利用可能です。
そのため、小さなAPIから本格的な開発まで、幅広い用途に対応できます。
今回はC#やASP.NET Core初心者でも気軽に体験できるよう、簡単なサンプルから、本番のAPIサーバーに適用できる構成の作り方までひと通り確認してみます。
環境構築
今回はWindows環境で、Visual Studio Codeで開発する場合を想定します。
- .NET SDKをインストールする
- VSCodeに拡張機能「C# Dev Kit」を追加する
- 空のフォルダを作成し、VSCodeで開く
- VSCodeターミナルを起動(Ctrl+Shift+@)し、以下のコマンドを入力する
dotnet new web -n <プロジェクト名>
cd <プロジェクト名>
dotnet new webを実行すると、Minimal API形式のASP.NET Coreプロジェクトが生成されます。
このテンプレートが、そのままシンプルなAPIの土台になります。
Minimal APIの基本
まずは、作成されたProgram.csを以下のように編集します。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// リソース'/'にGETされたときの処理
app.MapGet("/", () =>
{
// ステータスコード200(OK)とJSONボディを返す
return Results.Ok(new { message = "Hello World" });
});
app.Run();
アプリケーションを実行し、ブラウザで http://<your-host>:5220/ にアクセスするとJSONが表示されます。
※ポート番号は環境によって異なる場合があります。
これが最小構成のMinimal APIです。
レスポンス制御
Minimal APIでは Results を使ってHTTPレスポンスを作ります。
Results.Ok(object? value) // 200
Results.Created(string uri, object? value) // 201 uriはLocationヘッダーの値
Results.BadRequest(object? error) // 400
Results.InternalServerError() // 500
Results.StatusCode(int statusCode) // 指定のステータス
基本的には、オブジェクトを渡せばJSONとして返却されます。
ASP.NET Coreが自動的にシリアライズとContent-Typeの設定を行います。
パラメータの取得
パスやクエリ文字列から値を取得できます。
ルート定義と引数名が一致していれば自動的にバインドされます。
// URL例:/users/1?page=2
app.MapGet("/users/{id}", (int id, int? page) =>
{
return Results.Ok(new { id, page });
// レスポンスボディ: {"id":1,"page":2}
});
JSONボディの取得
ASP.NET Coreの機能で、JSONは自動でデシリアライズされます。
//リクエストボディ例:'{ "id": 34, "name": "Name" }'
app.MapPost("/users", (User user) => Results.Created($"/users/{user?.Id}", user));
app.Run();
// デシリアライズ用クラス
public record User(int Id, string Name);
HttpContextの取得
ASP.NET CoreのHttpContextを取得して、もっと複雑な処理も可能です。
以下はレスポンスヘッダをセットする例です。
app.MapGet("/", (HttpContext context) =>
{
// レスポンスの Cache-Control ヘッダを設定
context.Response.Headers.CacheControl = $"public,max-age=3600";
// レスポンスの独自ヘッダを設定
context.Response.Headers["X-Custom-Header"] = "XXXXX";
return Results.Ok(new { message = "OK" });
});
エンドポイントのグループ化とファイル分離
機能が増えてくると、すべてをProgram.csに書くのは管理が難しくなります。
エンドポイントをグループ化したり、拡張メソッドを使ってファイルを分割したりすることで、規模が大きくなっても構造を保ちやすくなります。
グループ化
Minimal APIでは、同じURLプレフィックスを持つエンドポイントを MapGroup を使ってまとめることができます。
これにより、APIの構造が整理され、読みやすくなります。
例えば users リソースのエンドポイントを定義する場合、次のように書くことができます。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 'users' リソースのグループ
var users = app.MapGroup("/users");
// GET /users/{id}
users.MapGet("/{id}", (int id) => Results.Ok(id));
// POST /users
users.MapPost("", (string user) => Results.Created($"/users/{user}", user));
app.Run();
拡張メソッド
拡張メソッドを使うと、エンドポイント定義をProgram.csから別ファイルに移すことができます。
例として、プロジェクト内にMapUserEndpointExtensions.csを作成します。
public static class MapUserEndpointExtensions
{
// WebApplicationを拡張する
public static void MapUserEndpoints(this WebApplication app)
{
// リソース'users'のグループ
var users = app.MapGroup("/users");
// GET /users/{id}
users.MapGet("/{id}", (int id) => Results.Ok(id));
// POST /users
users.MapPost("", (string user) => Results.Created($"/users/{user}", user));
}
}
Program.csにて、先ほど作成した MapUserEndpoints を呼び出します。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 拡張メソッドを呼び出す
app.MapUserEndpoints();
app.Run();
さいごに
Minimal APIは、C#でWeb APIを実装する際の有力な選択肢です。
記述は簡潔ですが、ASP.NET Coreの基盤はそのまま利用でき、複雑な要件も思いのままです。
C#でAPI開発を検討している方は、一度試してみてはいかがでしょうか。