API仕様書 (OpenAPI) の管理に.NET 10 (ASP.NET Core)を用いる
はじめに
OpenAPI / Swagger使ってますか?
最近はAPI仕様書として、OpenAPIを用いて管理するようになりつつあります。
一方で、yaml / jsonを用いて記述するため、以下の問題点もあります。
- そもそもyaml / jsonを直接書くのがつらい
- 長くて読みにくい
- コンテクストを圧迫するため、生成AIの料金の圧迫
また、gRPCの表現ができない、という弱点もあります。
このため、REST、OpenAPI、gRPCなどのプロトコルで共通するAPI形状を記述するために開発された専用の言語がTypeSpecです。
TypeSpecとは
TypeSpec (https://typespec.io/, https://github.com/microsoft/typespec/)とは、MS謹製のAPIを定義するための言語です。
複数のプロトコルを利用しているケースや、大規模なAPI仕様書の管理に使えるのではないかと期待されます。個人的には、4万行超のopenapi.yamlをTypeSpecに移行した話が印象に残っています。
しかし、まだまだ事例が少ないようで、2025/11/16時点で、Zennでトピックで見つかるのはOpenAPI 423件に対しTypeSpecは11件にすぎません。
メジャーバージョンになったのが2025/05/07 (typespec-stable@1.0.0)と最近で、周辺ライブラリも0系と発展途上です。
TypeSpecのジェネレーターは軒並み0系のため、現時点では、例えばopenapi-generator-cliのような別のツールを用いることになるでしょう。
最近は、生成AIにドキュメントを渡すというのが重要であることからも、なるべく文字数が少なく、かつ高品質な情報を渡せるというのは重要かと思います。
執筆時点でスター数5.5kであることから、非常に期待がなされていると言ってよいかと思います。
それ、ASP.NET Core (.NET 10) で実現できませんか?
TypeSpecでは、確かに、以下のことが可能です。
- TypeScriptに似た簡潔な記載方法
- 分割でのファイル定義
- 複数プロトコルへの対応
一方で、ほとんどの案件では、複数のプロトコルを同時に使うことや、数万行のOpenAPIによるAPI仕様書を見る機会は少ないでしょう。
どちらかと言えば、保守性・生成の品質・柔軟性などの方が重要なはずです。
そこで、ASP.NET Core (.NET 10)で管理するのはどうか?と考えてみました。
ASP.NET Coreでは、非常に簡単にOpenAPIの生成が可能になっています。通常、バックエンド開発で用いるものですが、割り切って管理に用いるのはどうか?と考えてみます。
※.NET 9時点で可能でしたが、.NET 10 LTSでは長期のサポートが保証されるため、.NET 10を前提として記載します。
TypeSpecをASP.NET Coreに書き換えてみた
サンプルとして、クイック スタート: TypeSpec と .NET を使用して新しい API プロジェクトを作成する での自動生成されるコードを丸っと.NET 10に置き換えてみます。
例えば、このmodelの表現では以下のようになります。
[Range]属性を用いてのバリデーションも可能で、表現力としては十分なものがあります。
C#では文字列リテラルのユニオン型が使えないため、enumで明示的に定義するのが明確な差異となります。
model Widget {
id: string;
weight: int32;
color: "red" | "blue";
}
public record Widget(
string Id,
int Weight,
WidgetColor Color
);
[JsonConverter(typeof(JsonStringEnumConverter<WidgetColor>))]
public enum WidgetColor
{
Red,
Blue
}
APIエンドポイントではこうです。ASP.NET Core側では、数行追記が必要です。
[Authorization]属性をつけることで、securityセクションの追加が可能です。
また、4xx系のエラーの追記、APIエンドポイントや、パスパラメーターへのdescriptionの記述も可能ですが、今回は省いています。
@route("/widgets")
@tag("Widgets")
interface Widgets {
@get list(): WidgetList | Error;
}
[ApiController]
[Route("/widgets")]
[Tags("Widgets")]
[Produces("application/json")]
public class WidgetsController : Controller
{
[HttpGet]
public WidgetList List()
{
throw new NotImplementedException();
}
}
左:TypeSpecの生成、右:.NET 10の生成です。
(注意:.NET 10は、現時点ではyaml形式の直接のCLI生成をサポートしていないので、手動変換している)


ASP.NET Coreである理由
OpenAPIの生成だけが目的ならば、様々な手法があります。
- Golang × swag https://github.com/swaggo/swag
- Hono × hono-openapi https://hono.dev/examples/hono-openapi
- Zod × zod-to-openapi https://github.com/asteasolutions/zod-to-openapi
- Laravel × L5-Swagger https://github.com/DarkaOnLine/L5-Swagger
- Laravel × Scribe https://scribe.knuckles.wtf/laravel/
しかし、動的型付けの言語では型定義が弱く、品質の高いOpenAPIを作ることが困難です。
また、静的型付けだとしても、TypeScriptはNode.js系のためエコシステムの移り変わりが激しすぎるため、仕様書を安定的に生成するという観点では、負債となるリスクもあります。モノレポの管理も考慮すべきですが、tsconfig.jsonの設定が複雑になることが多いです。
さらに、静的型付けだとしても、コメントで書いていく場合には、形式の間違いの可能性は非常に厄介な問題となります。
しかし、.NET10だと非常に強いメリットがあります。
- エコシステム自体の安定性・設定の容易性
- LTSによる後方互換性・保守性
- sln / slnxファイルによる一元管理
- ASP.NET core内蔵の設定の簡易さ
- 厳密な型定義
- C#の厳密な型定義
- アノテーションが属性による定義のため、アノテーションの形式チェックをビルドで可能
- ライブラリに固めることができるため、定義したコードをそのままASP.NET coreバックエンド開発に流用できる
※ .NET 8 LTSではSwashbuckle等採用のため、all-in-oneではなかった
※ .NET9から、Microsoft.AspNetCore.OpenApiとMicrosoft.Extensions.ApiDescription.Serverはあるが、LTSではない
スキーマ駆動開発では、OpenAPIの品質がそのまま生成コードに直結してしまうため、まず品質の高いOpenAPIが必要になります。
一方で、正確にOpenAPI自体を書く難易度自体は非常に高いと考えています。
書き捨てる思いで割り切ってASP.NET Coreを書き捨ててしまい、ひな形のOpenAPIを手に入れるだけでかなり開発としては楽になるのではないか、と思われます。
備考
- ASP.NET CoreにおけるOpenAPIのyamlでの生成はhttps://github.com/dotnet/aspnetcore/issues/61041で対応中のようですので、そのうちサポートされるかと思われます。
- ASP.NET Coreのwebサーバを立ち上げればyamlでも表示できるので、curlで取得するという手もあります。
Discussion