1. はじめに
以前の記事「初学者用:TypeSpecとOpenAPIの基本的概要」ではそれぞれの基本的な概念について触れましたが、今回は「実践的にどう使用するのか」について書いていこうと思います。OpenAPI(Swagger)のYAML管理に悩まされている方々へ、TypeSpecによるクリーンでモダンな設計手法について提案します。
2.TypeSpecでAPI設計を始める前に考えること
実践前に、改めて整理しておくべき「マインドセット」が3つあります。
TypeSpecとOpenAPIの役割分担
改めて、両者の関係性を再定義します。
TypeSpec: 「人間が設計するための言語」
OpenAPI: 「ツールやプログラムのための成果物」
「まず設計を整える」意識
YAMLを書いていると「どう記述するか(構文)」を考えがちですが、TypeSpecなら「どうあるべきか(設計)」に集中できます。
個人的には、コードを書く前に必要なインターフェースを整理すると設計しやすかったです。
3. 実務でのディレクトリ構成
TypeSpecはTypeScriptのようにファイルを分割・インポートできます。1ファイルに全てを詰め込まず、役割ごとに整理することができます。
3.1 基本、応用的な構成例
projectFolder
├── models.tsp #データモデル(User,Product)
├── api.tsp #APIエンドポイントの定義
└── commn.tsp #共通定義(エラー型、ページング)
projectFolder
├── models/
└── model.tsp #データモデル
├── routes/
└── api.tsp #APIエンドポイントの定義
└── namespace.tsp #共通のエンドポイント、namespace、URLなどの宣言
3.2 ファイルを分割する3つのメリット
-
影響範囲の最小化
修正が特定のファイル(例:User.tsp)に限定されるため、どこで変更されたかなど修正点がわかります。 -
「型の再利用」と「関心の分離」
データ構造(データモデルなど)とAPI定義を分けることで、共通のデータモデルを複数のAPIで使い回すことができるようになります。 -
エラー発見
ファイルをまたぐようなインポートも、TypeSpecのコンパイラがチェックしているので、コンパイル実行前にドキュメントの不整合を防ぐことができる。
4.実際のTypeSpecコード例
では実際にTypeSpecで定義を書き、期待される出力結果(OpenAPI)を見てみます。
namespace ProjectX {
@summary("ユーザモデル定義")
model User {
@summary("ユーザID")
userId:integer;
@summary("ユーザ名")
userName:string;
@summary("ロール情報")
role:roleData[]; #ロール権限モデル定義を参照
}
@summary("ロール権限モデル定義")
model roleData {
@summary("ロール権限")
roletype: 1|2;
@summary("役職名")
label:string;
}
}
namespace ProjectX.Application {
@get
@summary("ユーザ一覧取得")
@route("projectx/api/user/")
op getUserData(
@path
@summary("企業ID")
comapanyId:integer;
):User;
}
openapi: 3.0.0
info:
title: ProjectX API
version: 0.0.0
tags: []
paths:
/projectx/api/user/{comapanyId}:
get:
summary: ユーザ一覧取得
operationId: getUserData
parameters:
- name: comapanyId
in: path
required: true
description: 企業ID
schema:
type: integer
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
summary: ユーザモデル定義
properties:
userId:
type: integer
description: ユーザID
userName:
type: string
description: ユーザ名
role:
type: array
items:
$ref: '#/components/schemas/roleData'
description: ロール情報
required:
- userId
- userName
- role
roleData:
type: object
summary: ロール権限モデル定義
properties:
roletype:
type: integer
description: ロール権限
enum:
- 1
- 2
label:
type: string
description: 役職名
required:
- roletype
- label
※@summaryや@routeなどの「デコレータ」については別の記事でまとめようと考えています。
5. まとめ
TypeSpecを実務に取り入れることで、YAML管理から解放され、API設計に注力できます。
今回のポイントは以下の通りです。
・TypeSpec = 設計、OpenAPI = 「成果物」と割り切る。
・ディレクトリ分割により、保守性と再利用性を高める。
・コンパイラの力を借りて、不整合のないドキュメントを維持する。
私は最初からAPI設計をTypeSpecで行い、コンパイルしてOpenAPIを生成しました。
しかし、従来のAPI設計手法、YAMLの管理を知れば知るほどTypeSpecでのモダンAPI設計がメジャーになっていってほしいと思います。