.NET Minimal APIs完全ガイド
.NET Minimal APIs 実践ガイド:軽量で高速な Web API 開発
はじめに:Controller地獄からの解放
「またController作って、Model作って、Service作って...」 「ただHello World返したいだけなのに、なんでこんなにファイルが必要なの?」
正直、ASP.NET Coreの伝統的なControllerパターンに疲れていました。小さなAPIを作るのに、大量のボイラープレートコード...
そんな時に.NET 6で登場したのがMinimal APIsです。初めて使った時の衝撃は今でも忘れられません。
var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
app.Run();
たった3行でWeb APIが動いたんです!「これだよ、これが欲しかったんだよ!」と叫んでしまいました。
実際に使ってみて分かったこと
シンプルさの衝撃
従来のControllerパターンと比較してみましょう。
Controller時代:
- UserController.cs
- IUserService.cs
- UserService.cs
- UserModel.cs
- Startup.cs
- Program.cs
最低でも6ファイル。それぞれにボイラープレートコード...
Minimal APIs:
app.MapGet("/api/users/{id}", async (int id, IUserService service) =>
await service.GetUserAsync(id) is { } user
? Results.Ok(user)
: Results.NotFound());
1ファイル、3行で完結!このシンプルさに感動しました。
DI(依存性注入)もそのまま使える
「Minimalだから機能が少ないんでしょ?」
いいえ、全然そんなことはありません!ASP.NET Coreの強力なDIはそのまま使えます。
// サービスの登録はいつも通り
builder.Services.AddScoped<IUserService, UserService>();
// エンドポイントで自動注入!
app.MapGet("/users", (IUserService service) => service.GetAllAsync());
初めてこれを見た時、「魔法みたい!」と思いました。
エンドポイントが増えてきた時の整理術
グループ化で見通しをよくする
最初は全部Program.csに書いていました。でも、エンドポイントが20個超えたあたりで「これはマズい...」と気づきました。
そこで発見したのがMapGroupの威力です:
// ユーザー関連をグループ化
var users = app.MapGroup("/api/users")
.RequireAuthorization(); // グループ全体に認証を適用!
users.MapGet("/", GetAllUsers);
users.MapGet("/{id}", GetUserById);
users.MapPost("/", CreateUser);
嬉しかったポイント:
- URLの共通部分を1箇所で管理
- 認証設定もまとめて適用
- Swaggerでも自動的にグループ化される
バージョニングも簡単に
「APIのバージョン管理どうしよう...」という悩みも、Minimal APIsなら簡単でした:
var v1 = app.MapGroup("/api/v1");
var v2 = app.MapGroup("/api/v2");
// v1とv2で挙動を変えられる!
v1.MapGet("/users", GetUsersV1);
v2.MapGet("/users", GetUsersV2); // 新しい機能追加
これで後方互換性を保ちながら、新機能を追加できるようになりました。
認証も簡単に実装できた
「Minimal APIsって、認証とか複雑なことはできないんでしょ?」
最初はそう思っていました。でも、全然そんなことはありませんでした!
JWT認証の実装:
// 認証を有効化
builder.Services.AddAuthentication().AddJwtBearer();
// エンドポイントで使用
app.MapGet("/api/secure", () => "Secret data!")
.RequireAuthorization();
たったこれだけで、JWT認証が動きました。もちろん、細かい設定も可能です。
役割ベースの認可も簡単:
app.MapPost("/api/admin/users", CreateUser)
.RequireAuthorization("AdminOnly");
app.MapGet("/api/users/{id}", GetUser)
.RequireAuthorization(); // ログインユーザーのみ
Controllerの時と同じように、柔軟な認証・認可が実現できて安心しました。
ミドルウェアもフィルターも使える!
「Minimal APIsは機能が制限されてるんでしょ?」という誤解をよく聞きます。
でも実際は、ASP.NET Coreの強力な機能はほぼ全部使えるんです!
ミドルウェアの例: 全リクエストのログを取りたい時、従来通りミドルウェアが使えます:
app.Use(async (context, next) =>
{
var start = DateTime.Now;
await next();
var duration = DateTime.Now - start;
Console.WriteLine($"{context.Request.Path}: {duration.TotalMilliseconds}ms");
});
エンドポイントフィルター: 特定のエンドポイントだけに処理を追加したい時:
app.MapPost("/api/users", CreateUser)
.AddEndpointFilter(async (context, next) =>
{
// バリデーション処理
var result = await next(context);
// 後処理
return result;
});
Controllerでできたことは、Minimal APIsでもできる。これが分かった時、完全に移行を決意しました。
パフォーマンスの衝撃的な改善
起動時間が10分の1に!
従来のController版とMinimal APIs版で起動時間を比較してみました:
Controller版:
- コールドスタート:2.3秒
- メモリ使用量:180MB
Minimal APIs版:
- コールドスタート:0.2秒
- メモリ使用量:60MB
この差は本当に衝撃的でした。特にサーバーレス環境では、この速さが大きな武器になります。
キャッシングも簡単
「同じデータを何度も取得するのは無駄...」
そんな時は、.NET 7で追加されたOutput Cachingが便利です:
app.MapGet("/api/products", GetProducts)
.CacheOutput(policy => policy.Expire(TimeSpan.FromMinutes(5)));
たった1行でレスポンスキャッシュが有効に!これでデータベースへの負荷が激減しました。
大量データも怖くない
10万件のデータをCSVでエクスポートする要求がありました。普通にやったらメモリ不足で死にます...
でも、IAsyncEnumerableを使えば:
app.MapGet("/api/export", async (HttpContext context) =>
{
context.Response.ContentType = "text/csv";
await foreach (var item in GetDataAsync())
{
await context.Response.WriteAsync($"{item.Id},{item.Name}\n");
}
});
メモリ使用量を抑えながら、大量データを扱えるようになりました。
テストもドキュメントも充実
テストが書きやすい!
「Minimal APIsはテストが書きにくいのでは?」という心配は無用でした。
WebApplicationFactoryを使えば、統合テストも簡単:
[Fact]
public async Task ユーザー作成APIのテスト()
{
// テスト用のクライアントを作成
var client = _factory.CreateClient();
// APIを呼び出し
var response = await client.PostAsJsonAsync("/api/users", new { Name = "Test" });
// 結果を検証
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
}
Controller時代と同じようにテストが書けて安心しました。
Swagger/OpenAPIも完璧
APIドキュメントの自動生成も、もちろん対応しています:
app.MapGet("/api/users/{id}", GetUser)
.WithName("GetUser")
.WithSummary("ユーザー情報を取得")
.WithDescription("指定されたIDのユーザー情報を返します")
.Produces<User>(200)
.Produces(404);
開発時にSwagger UIを開けば、美しいAPIドキュメントが自動生成されています。これは本当に便利!
リアルタイム通信もできちゃう
SignalRとの相性も抜群
「Minimal APIsでリアルタイム通信は無理でしょ?」
いいえ、SignalRも普通に使えます!
// SignalR Hubを追加
builder.Services.AddSignalR();
app.MapHub<ChatHub>("/chat");
// REST APIから通知を送る
app.MapPost("/api/notify", async (IHubContext<ChatHub> hub, string message) =>
{
await hub.Clients.All.SendAsync("NewMessage", message);
return Results.Ok();
});
チャット機能や通知機能も、Minimal APIsで簡単に実装できました。
実運用での気づき
デプロイが爆速に
Dockerイメージのサイズを比較してみました:
Controller版: 250MB Minimal APIs版: 80MB
サイズが3分の1に!デプロイ時間も大幅に短縮されました。
ヘルスチェックも簡単
app.MapHealthChecks("/health");
たった1行でヘルスチェックエンドポイントが完成。Kubernetesとの相性も抜群です。
まとめ:Minimal APIsに移行して本当に良かった!
1年前、「Minimal APIsって本当に実用的なの?」と疑っていた自分に言いたい。「今すぐ使い始めろ!」と。
移行して得られたもの:
- 開発速度が2倍に向上
- コードベースが50%削減
- 新人エンジニアの学習期間が半分に
- パフォーマンスが劇的に改善
一番の驚き: 機能を削ぎ落としたわけではないのに、シンプルになった。これがMinimal APIsの真の価値だと思います。
感動した瞬間: 新卒エンジニアが「APIってこんなに簡単に作れるんですね!」と目を輝かせた時。複雑さに怯えることなく、本質的な開発に集中できる。これこそが理想の開発環境です。
正直な感想: 最初は「Minimalって言うけど、結局複雑になるんでしょ?」と思っていました。でも、1年使ってみて分かりました。本当に必要な機能だけを、最もシンプルな形で提供してくれる。これがMinimal APIsの哲学なんです。
もし、まだController地獄で苦しんでいる方がいたら、ぜひMinimal APIsを試してみてください。きっと、Web API開発の概念が変わるはずです。
エンハンスド株式会社では、Minimal APIsを活用した高性能なWeb APIの設計・開発を支援しています。「既存のAPIをモダナイズしたい」「パフォーマンスを改善したい」という方は、お気軽にご相談ください。一緒に、シンプルで強力なAPIを作りましょう!
参考リンク
- .NET Minimal APIs 公式ドキュメント
- Minimal APIs サンプル集
- パフォーマンスベンチマーク
- .NET 8の新機能
- David Fowler's Minimal API Examples
執筆者: エンハンスド株式会社 API開発チーム
公開日: 2025年9月5日
カテゴリ: .NET, Web API, Minimal APIs
タグ: #DotNet #MinimalAPIs #WebAPI #Performance #モダナイゼーション