🦔

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生成をサポートしていないので、手動変換している)

Modelの場合

Pathの場合

ASP.NET Coreである理由

OpenAPIの生成だけが目的ならば、様々な手法があります。

しかし、動的型付けの言語では型定義が弱く、品質の高い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.OpenApiMicrosoft.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で取得するという手もあります。

サンプルコード

参考文献

GitHubで編集を提案

Discussion