API契約は、Wikiの図、前四半期にエクスポートされたPostmanコレクション、そして実装から2リリース分遅れたMarkdownドキュメントに分散しがちです。これらが食い違うと、チームは推測で実装することになります。推測はインテグレーション障害の原因になります。
API仕様をコードとして扱うと、この問題を減らせます。OpenAPIファイルを1つ作成し、Gitにコミットし、通常のソースコードと同じようにレビューします。その仕様からモック、テスト、ドキュメント、SDKを生成します。仕様は「後で更新する資料」ではなく、全員が従う契約になります。
この記事では、Spec-as-Codeの考え方、OpenAPIをGit管理する理由、そして実装しやすいワークフローを説明します。
Spec-as-Codeとは何か
Spec-as-Codeとは、API定義をバージョン管理されたプレーンテキストファイルとして扱うことです。共有リンクのドキュメントやツール内のデータではなく、git diff、ブランチ、マージ、レビューができるファイルにします。
この考え方はDocs-as-Codeに近いものです。Docs-as-Codeでは、ドキュメントをコードと同じリポジトリに置き、同じパイプラインで管理します。Spec-as-Codeでは、その対象をAPI契約に広げます。
実務では、OpenAPIドキュメント、つまりYAMLまたはJSONファイルを成果物の中心にします。
api/
openapi.yaml
src/
...
開発者が/users/{id}のレスポンスを確認したい場合は、WikiではなくOpenAPIファイルを見ます。QAはその仕様に対してテストを作ります。外部パートナーは仕様から生成されたSDKやドキュメントを使います。
つまり、1つの仕様ファイルから複数の成果物を生成します。
なぜ仕様をコードのように扱うのか
仕様をGit内のファイルにすると、ソースコードで使っているワークフローをそのまま適用できます。
1. プルリクエストで変更をレビューできる
エンドポイントの変更はPRの差分として確認できます。
たとえば、次のような変更がすぐに見えます。
status:
type: string
- enum: [pending, shipped, delivered]
+ enum: [pending, shipped, delivered, canceled]
レビュー担当者は以下を確認できます。
- フィールドが追加・削除されたか
- ステータスコードが変更されたか
- レスポンス形式が後方互換性を壊していないか
- 既存クライアントに影響があるか
破壊的変更は本番で発覚するのではなく、マージ前のPRで議論できます。これはGitネイティブAPIワークフローの中心です。
2. YAMLは差分を読みやすい
OpenAPIをYAMLで管理すると、差分が読みやすくなります。
paths:
/orders/{orderId}:
get:
summary: Get an order by ID
バイナリ形式のエクスポートや、ツール内だけで完結する変更履歴と比べると、Git上のYAMLは扱いやすいです。
Gitに仕様を置けば、以下が機能します。
git diffgit blame- コミット履歴
- タグ
- ブランチ
git revert
3. APIの履歴を監査できる
すべての仕様変更には、コミット、著者、タイムスタンプが付きます。
たとえば次のような運用ができます。
git tag api-v1.2.0
git checkout -b api-v2-redesign
git revert <commit>
リリースごとに仕様へタグを付けると、過去バージョンの契約も追跡できます。タグ付けとブランチ戦略については、GitでのOpenAPIバージョン管理も参考になります。
4. 仕様を唯一の真実の情報源にできる
モック、テスト、ドキュメント、SDKを同じOpenAPIファイルから生成すれば、それぞれが別々に乖離しにくくなります。
| 懸念事項 | ホスト型ツールでの仕様 | コードとしてのAPI仕様 |
|---|---|---|
| 変更レビュー | 手動、見落としやすい | PR差分、レビューでブロック可能 |
| 履歴 | 制限されるかベンダーロックされる | 完全なGitログ |
| ロールバック | 多くの場合手動 | git revert |
| 真実の情報源 | 曖昧 | コミットされたファイル |
| CI統合 | 後付け | ネイティブ |
成果物としてのOpenAPI
OpenAPIは機械可読で、モック、テスト、ドキュメント、SDK生成に広く対応しています。
以下は、リポジトリに置けるOpenAPI 3.1ファイルの最小例です。
openapi: 3.1.0
info:
title: Orders API
version: 1.2.0
paths:
/orders/{orderId}:
get:
summary: Get an order by ID
operationId: getOrder
parameters:
- name: orderId
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: The requested order
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
"404":
description: Order not found
components:
schemas:
Order:
type: object
required: [id, status, total]
properties:
id:
type: string
format: uuid
status:
type: string
enum: [pending, shipped, delivered]
total:
type: number
format: float
このファイルが契約です。
たとえばOrderにcurrencyを追加する場合、変更は明確です。
required: [id, status, total]
properties:
total:
type: number
format: float
+ currency:
+ type: string
+ example: JPY
このように、API仕様をapi/openapi.yamlなどの固定パスに置き、サービスコードの近くで管理します。
仕様から生成するもの
OpenAPIファイルを1つ管理するだけでは十分ではありません。重要なのは、その仕様から実際の成果物を生成することです。
モックを生成する
モックサーバーを仕様に合わせると、バックエンド実装前でもフロントエンドやモバイルチームが統合を開始できます。
流れは次のようになります。
-
api/openapi.yamlを更新する - モックサーバーを仕様から起動する
- フロントエンドがモックAPIに接続する
- 仕様変更時にモックも更新する
これにより、実装待ちによるブロッカーを減らせます。
契約テストを追加する
稼働中のAPIが仕様と一致しているかをCIで検証します。
確認すべき例は以下です。
- 仕様にないフィールドを返していないか
- 必須フィールドが欠落していないか
- ステータスコードが仕様と一致しているか
- レスポンスの型が一致しているか
契約テストを入れると、仕様と実装の乖離を顧客より先にビルドで検出できます。
ドキュメントを生成する
エンドポイント表を手書きするのではなく、OpenAPIから参照ドキュメントをレンダリングします。
仕様が更新されると、ドキュメントも同じ定義から更新されます。つまり、ドキュメントは「仕様を説明する別ファイル」ではなく、「仕様そのものを表示したもの」になります。
SDKを生成する
同じOpenAPIファイルから、複数言語のクライアントライブラリを生成できます。
たとえば、パートナーや社内チームに次のような型付きSDKを提供できます。
- TypeScript
- Python
- Java
- Go
- Kotlin
仕様を更新し、SDKを再生成すれば、クライアント側も最新の契約に追従しやすくなります。
Apidogで仕様を唯一の真実の情報源にする
Spec-as-Codeを手作業で構築する場合、以下を組み合わせる必要があります。
- OpenAPIエディタ
- モックサーバー
- ドキュメントジェネレーター
- 契約テスト
- Git同期
- CI設定
Apidogは、これらを1つのワークフローにまとめます。
ApidogのSpec-Firstモードでは、OpenAPIファイルを権威ある定義として扱います。仕様に沿ってエンドポイントを設計し、モック、テスト、ドキュメントを同期させます。
実務で重要なのは、双方向Git同期です。
ApidogはリポジトリからOpenAPIファイルを読み込み、変更を書き戻せます。そのため、Git内のopenapi.yamlとApidog内のプロジェクトを一致させられます。
使い分けはシンプルです。
- YAMLを直接編集したい場合: エディタで
openapi.yamlを編集する - 視覚的に設計したい場合: Apidog上で編集する
- どちらの場合も: 最終的な変更はGit上の仕様に反映する
これにより、チームは視覚的なAPI設計ツールを使いながら、PRレビューとGit履歴を維持できます。仕様変更をGitHubへ同期する方法は、GitHubにOpenAPI仕様を同期する方法を参照してください。
結果として、OpenAPIファイルは唯一の真実の情報源であり続けます。視覚的なツールは仕様の上にある編集レイヤーであり、仕様そのものを置き換えるものではありません。
よくある落とし穴
Spec-as-Codeはシンプルですが、導入時によく失敗するパターンがあります。
仕様と実装が乖離する
仕様を書くだけでは不十分です。実装が仕様に一致しているかを検証しなければ、両者は徐々に乖離します。
対策は、CIに契約テストを追加することです。
PR作成
↓
OpenAPIのlint
↓
契約テスト
↓
マージ
不一致があれば、顧客ではなくビルドが検出します。
生成元が複数ある
仕様を手書きするのか、コードアノテーションから生成するのかを決めてください。
混在すると、どちらが正しいのか分からなくなります。
悪い例:
コードアノテーション → OpenAPI生成
手書きOpenAPI → 別の変更
Apidog上の仕様 → さらに別の変更
良い例:
OpenAPIファイルを唯一の真実の情報源にする
または、
コードアノテーションを唯一の生成元にする
どちらでも構いません。重要なのは、マスターコピーを1つにすることです。
仕様をドキュメントとしてしか使わない
読むだけの仕様はドキュメントです。
モック、テスト、SDK、ドキュメントを生成する仕様は契約です。
Spec-as-Codeの価値は、ファイルを置くことではなく、そのファイルから下流の成果物を動かすことにあります。
レビューなしでマージする
Gitに置いただけでは不十分です。レビューされない仕様変更は、ただのファイル変更です。
最低限、次のルールを設定します。
- API仕様の変更はPR必須
- レビュー担当者を指定する
- 破壊的変更は明示的にコメントする
- CIでOpenAPIの妥当性を検証する
始め方
Spec-as-Codeは一度に全部導入する必要はありません。段階的に進められます。
1. OpenAPIファイルをコミットする
まず、仕様ファイルをリポジトリに置きます。
api/openapi.yaml
既存の仕様がある場合は、エクスポートしてこの場所に移動します。
2. PRレビューを必須にする
仕様変更がコード変更と同じレビューゲートを通るようにします。
たとえば、ブランチ保護ルールで以下を設定します。
- PR必須
- 1人以上のレビュー必須
- CI成功必須
3. 1つの成果物を生成する
最初からすべてを自動化する必要はありません。
まずは次のどちらかから始めます。
- モック
- ドキュメント
OpenAPIファイルを更新したら、生成物も更新されるようにします。
4. CIでOpenAPIを検証する
すべてのPRで仕様の妥当性をチェックします。
チェック対象は以下です。
- YAML構文
- OpenAPIスキーマの妥当性
- 必須項目の欠落
- 命名規則
- 破壊的変更
5. 契約テストを追加する
最後に、稼働中のサービスが仕様と一致しているかを検証します。
これでフィードバックループが閉じます。
仕様を書く
↓
実装する
↓
CIで仕様と実装を照合する
↓
不一致があれば失敗する
この状態になると、仕様は単なるドキュメントではなく、強制力のある契約になります。
Spec-as-Codeの導入は小さく始められます。まずOpenAPIファイルをGitに置き、PRでレビューし、1つの成果物を生成します。そこからモック、ドキュメント、SDK、契約テストへ広げていけば、API契約の乖離を継続的に減らせます。
視覚的な編集とGit同期を組み込みたい場合は、ApidogのSpec-Firstモードをお試しください。OpenAPIファイルを唯一の真実の情報源として維持できます。
よくある質問
「API Spec as Code」は「Docs-as-Code」と同じですか?
同じ哲学を共有していますが、対象が異なります。
Docs-as-Codeはドキュメントをバージョン管理下に置きます。Spec-as-CodeはAPI契約そのものをバージョン管理下に置きます。
ただし、コミットされたOpenAPI仕様からドキュメントを生成する場合、両者は自然に連携します。
仕様ファイルはどのフォーマットを使うべきですか?
一般的にはYAML形式のOpenAPIが扱いやすいです。
理由は次のとおりです。
- PRで差分を読みやすい
- 人間が編集しやすい
- ツールが解析しやすい
- モック、テスト、SDK生成に対応しやすい
JSONも使えますが、日常的なレビューではYAMLの方が見通しがよくなります。
仕様が実際のAPIから乖離するのをどう防ぎますか?
CIに契約テストを追加します。
稼働中のサービスをOpenAPI仕様と照合し、以下のような不一致があればビルドを失敗させます。
- 宣言されていないフィールドを返す
- 必須フィールドを返さない
- 型が仕様と異なる
- ステータスコードが仕様と異なる
このフィードバックループが、仕様を希望的なドキュメントから実行可能な契約へ変えます。



Top comments (0)