ほとんどのAPIチームは、契約を後回しにしがちです。先にコードを書き、そこから仕様書を生成し、時間が経つにつれてコードと仕様が乖離していきます。GitネイティブAPIデザインでは、この順序を逆にします。API契約をソースコードとして扱い、Gitでバージョン管理し、アプリケーションコードと同じようにレビューします。
このガイドでは、特定のツールではなく、Gitを中心にしたAPI設計の進め方を扱います。ブランチで契約を設計し、プルリクエストでレビューし、コミット済みの仕様からモック、テスト、ドキュメントを生成する流れを実装できるようにします。
Spec-Firstツールの概要や製品ウォークスルーを知りたい場合は、gitネイティブAPIワークフローに関する補足記事も参照してください。この記事では、実践的なワークフローに絞って説明します。
API作業における「Gitネイティブ」とは
Gitネイティブとは、API定義をプレーンテキストファイルとしてリポジトリに置くことです。独自のクラウドDBやベンダーUIの内部データではなく、コードの隣にある .yaml または .json ファイルを正とします。
たとえば、次のような構成です。
repo/
api/
openapi.yaml
src/
...
.github/
workflows/
api-lint.yml
多くのAPIデザインツールでは、契約の正本がクラウド側にあります。Web UIで編集し、必要に応じて仕様をエクスポートする形です。この場合、Gitリポジトリに残るのは古いスナップショットになりがちで、Git履歴からAPIがどう進化したかを追跡できません。
Gitネイティブモデルでは、main ブランチ上の仕様ファイルが契約です。GUI、モック、ドキュメント、テストはすべて、そのファイルに対するビューまたは派生成果物として扱います。
GitネイティブなAPI設計には、次の3つの条件があります。
- 仕様がリポジトリ内のテキストファイルである
- 変更がブランチ、コミット、PR、マージを通じて進む
- モック、ドキュメント、テスト、クライアントがコミット済み仕様から生成される
APIをGitで設計・開発する理由
コードをGitで管理するなら、API契約も同じように管理すべきです。理由は実装上のメリットが大きいからです。
1. 履歴を追跡できる
「いつ cursor ページネーションを追加したのか?」という質問には、git log で答えられます。
git log -p -- api/openapi.yaml
該当コミットには、変更内容、作成者、日付、コミットメッセージが残ります。別の変更履歴ツールやスクリーンショットを探す必要はありません。
2. 責任範囲を確認できる
仕様ファイルに対して git blame を実行すると、誰がどの行を変更したかを確認できます。
git blame api/openapi.yaml
混乱を招くフィールド名やレスポンス定義があれば、それを追加したPRまで遡れます。設計判断の議論もPR上に残ります。
3. ロールバックできる
問題のあるAPI設計をマージしてしまった場合でも、Gitなら git revert で戻せます。
git revert <commit-sha>
仕様が戻れば、そこから生成されるモック、ドキュメント、クライアント、テストも元の契約に戻せます。個別のツールで手動修正する必要はありません。
4. PRで設計レビューできる
API設計は、実装前にレビューするほど安く修正できます。PRでは、レビュー担当者が追加・削除された行に直接コメントできます。
+ /users/{userId}/invoices:
+ get:
+ operationId: listUserInvoices
命名、ステータスコード、ページネーション、エラー形式などを、ハンドラーコードを書く前に合意できます。
単一の信頼できる情報源があることが重要です。契約が main の1ファイル、または管理された複数ファイルにあるなら、フロントエンド、バックエンド、QA、ドキュメント担当者が同じ定義を参照できます。これは、GitベースのAPI仕様ワークフローの中心的な価値です。
GitネイティブAPIデザインループ
GitネイティブなAPI設計は、次のループで進めます。
- 契約を設計する
- 仕様ファイルをコミットする
- PRを開く
- 設計レビューを行う
- マージ後に実装する
実装はマージ後です。コードが先ではありません。
例: 請求書一覧APIを追加する
ブランチを作成します。
git checkout -b feat/api-invoices-list
openapi.yaml にエンドポイントを追加します。
# openapi.yaml
paths:
/users/{userId}/invoices:
get:
operationId: listUserInvoices
summary: ユーザーの請求書を一覧表示
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
- name: status
in: query
required: false
schema:
type: string
enum: [draft, open, paid, void]
responses:
"200":
description: 請求書のページ
content:
application/json:
schema:
$ref: "#/components/schemas/InvoiceList"
"404":
description: ユーザーが見つかりません
変更を小さくコミットします。
git add api/openapi.yaml
git commit -m "GET /users/{userId}/invoices 契約を追加"
PRを開くと、レビュー担当者は次の点を確認できます。
- パス名は既存APIと一貫しているか
-
operationIdは明確か -
statusの enum は十分か - ページネーションが必要か
-
404は適切か - エラーレスポンス形式は既存APIと一致しているか
PRが承認されたら main にマージします。その後、バックエンド実装、フロントエンド開発、モック、テストを同じ契約に基づいて進めます。
これが スペックファーストAPI開発 の実践です。合意された契約が、実装より先に存在します。
API契約のブランチ戦略
API契約の変更も、通常のコード変更と同じように扱います。1つのPRには、1つの論理的な変更だけを含めます。
おすすめは、変更の種類が分かるブランチ名を使うことです。
| 変更の種類 | ブランチプレフィックス | 例 | レビューの重み |
|---|---|---|---|
| 新しいエンドポイント | feat/api- |
feat/api-invoices-list |
標準 |
| 追加フィールド | feat/api- |
feat/api-invoice-currency |
軽い |
| 破壊的変更 | break/api- |
break/api-remove-legacy-id |
重い、承認必須 |
| 仕様のバグ修正 | fix/api- |
fix/api-status-enum-typo |
軽い |
| リファクタリングのみ | chore/api- |
chore/api-reorder-schemas |
軽い |
break/api- という名前は、レビュー担当者に「既存コンシューマへの影響を必ず確認する」ことを示します。chore/api- は意味的な変更がないことを示すため、レビュー負荷を下げられます。
トランクベースかGitflowか
API仕様には、短命ブランチを使うトランクベース開発が向いています。
| モデル | 最適なケース | APIでのトレードオフ |
|---|---|---|
| トランクベース | 継続的デリバリー、小規模〜中規模チーム | 契約が小さく進化し、マージ競合が少ない |
| Gitflow | スケジュールされたリリース、規制の強い環境 |
develop や release で仕様が分岐し、マージが大きくなりやすい |
ほとんどのAPIチームでは、短命ブランチ + 小さなPRを推奨します。長期間のブランチでは、複数チームが同じYAMLを編集し、マージ競合が発生しやすくなります。
プルリクエストでのAPIデザインレビュー
仕様PRは構文チェックではなく、設計レビューです。レビューでは、少なくとも次の観点を確認します。
既存コンシューマを壊さないか
次の変更は破壊的変更になり得ます。
- フィールドを削除する
- パス名を変更する
- レスポンス型を厳格化する
- 必須フィールドを追加する
- enum の値を削除する
- ステータスコードを変更する
たとえば、次の差分は enum への値の追加なので、通常は後方互換です。
parameters:
- name: status
in: query
schema:
type: string
- enum: [draft, open, paid, void]
+ enum: [draft, open, paid, void, uncollectible]
一方、void を削除すると、その値を使っているクライアントを壊す可能性があります。
命名が一貫しているか
既存APIがコレクションに複数形名詞を使っているなら、新しいAPIも合わせます。
/users
/users/{userId}/invoices
エラー形式も統一します。
{
"code": "USER_NOT_FOUND",
"message": "ユーザーが見つかりません"
}
新しいエンドポイントだけ別の形式を返すと、クライアント実装が複雑になります。
差分が読みやすいか
YAMLは差分が大きくなりがちです。次のルールを決めておくと、レビューしやすくなります。
- キーの順序を固定する
- フォーマッターを使う
- パスを一定の順序で並べる
- 意味のない並び替えをPRに含めない
- 大きなリファクタリングと機能追加を同じPRに入れない
レビュー担当者には、アプリケーションコードと同じように仕様ファイルへインラインコメントしてもらいます。議論が該当行に紐づき、マージ後も履歴として残ります。
設計から開発へ
契約が main に入ったら、それをダウンストリーム成果物のソースにします。
1. コードを生成する
openapi-generator のようなツールを使うと、コミット済みのOpenAPIファイルからサーバースタブや型付きクライアントを生成できます。
例:
openapi-generator-cli generate \
-i api/openapi.yaml \
-g typescript-fetch \
-o generated/client
バックエンドでは、生成された型やスタブにビジネスロジックを実装します。リクエストとレスポンスの形状は、仕様に合わせて生成されます。
2. モックを起動する
モックサーバーは仕様を読み込み、エンドポイントごとのサンプルレスポンスを返します。これにより、バックエンド実装前でもフロントエンド開発を開始できます。
npx prism mock api/openapi.yaml
3. 契約テストを実行する
契約テストでは、実行中のAPIが仕様に一致しているかを検証します。
チェックする内容の例:
- ステータスコード
- レスポンスヘッダー
- JSONスキーマ
- 必須フィールド
- enum 値
- エラーレスポンス形式
仕様と実装が乖離した場合、CIを失敗させます。
4. ドキュメントを生成する
APIリファレンスはOpenAPIファイルから生成します。契約が変われば、ドキュメントも同じコミットで変わります。
手書きのドキュメントを別管理すると、更新漏れが発生します。Gitネイティブな運用では、ドキュメントも仕様から派生させます。
チームの成長に対応する規約
GitネイティブAPI設計をチームで続けるには、早い段階で規約を決めます。
1. 単一ファイルか分割ファイルかを決める
小規模APIなら、単一の openapi.yaml で十分です。
api/
openapi.yaml
エンドポイントが増えてきたら、$ref で分割します。
api/
openapi.yaml
paths/
users.yaml
invoices.yaml
schemas/
user.yaml
invoice.yaml
ビルド時に1つの仕様へバンドルします。
npx @redocly/cli bundle api/openapi.yaml -o dist/openapi.yaml
2. バージョン管理を明示する
OpenAPIの info.version を更新し、セマンティックバージョニングに従います。
openapi: 3.1.0
info:
title: Billing API
version: 1.4.0
目安は次の通りです。
- パッチ: 説明文の修正、仕様上の誤記修正
- マイナー: 後方互換なエンドポイントやフィールドの追加
- メジャー: 破壊的変更
破壊的変更では、必要に応じて /v2/ のような新しいパスプレフィックスを使います。
3. CHANGELOG.md を置く
Git履歴は正確ですが、コンシューマが読むには細かすぎます。仕様の隣に変更履歴を置きます。
# API Changelog
## 1.4.0
- `GET /users/{userId}/invoices` を追加
- `Invoice.status` に `uncollectible` を追加
## 1.3.1
- `Invoice.currency` の説明を修正
4. CODEOWNERS で仕様を保護する
API契約の変更には、API管理者のレビューを必須にします。
# .github/CODEOWNERS
/api/openapi.yaml @api-stewards
/api/paths/ @api-stewards
/api/schemas/ @api-stewards
これにより、善意の変更でも一貫性のない設計がマージされるのを防げます。
5. CIでリンティングする
仕様のスタイルや一貫性は、人間のレビュー前にCIで検出します。
# .github/workflows/api-lint.yml
name: API Lint
on:
pull_request:
paths:
- "api/**"
jobs:
spectral:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Spectral
run: npx @stoplight/spectral-cli lint api/openapi.yaml --fail-severity warn
CIリンティングと CODEOWNERS を組み合わせると、すべての契約変更に対して自動チェックと人間のレビューを強制できます。
よくある落とし穴と回避策
仕様とコードが乖離する
最も危険なのは、仕様ではある形を定義しているのに、実行中のAPIが別の形を返すことです。
回避策は、CIで契約テストを実行することです。
PR作成
-> API lint
-> サーバー起動
-> 契約テスト
-> 仕様とレスポンスを検証
-> 不一致なら失敗
乖離を本番障害ではなく、パイプラインの失敗として検出します。
PRが大きすぎる
20個のエンドポイントを1つのPRに入れると、レビューは形だけになります。
回避策:
- 1 PR = 1 エンドポイント
- 1 PR = 1 変更目的
- リファクタリングと機能追加を分ける
- 破壊的変更は専用PRにする
小さい差分ほど、実際にレビューされます。
手書き成果物が増える
クライアント、スタブ、ドキュメントを手書きすると、仕様とズレます。
回避策:
- クライアントは仕様から生成する
- サーバースタブも仕様から生成する
- ドキュメントも仕様から生成する
- 生成手順をCIまたはビルドスクリプトに含める
手書きのAPI成果物は、乖離の兆候として扱います。
YAMLのマージ競合が増える
長期間のブランチで同じ openapi.yaml を編集すると、競合が起きやすくなります。
回避策:
- 短命ブランチを使う
- 小さなPRにする
- キー順序を固定する
- ファイルをリソース単位に分割する
- 意味のない整形変更を避ける
トランクベース開発と小さなPRを組み合わせると、競合の多くは発生前に防げます。
Apidogの役割
GitネイティブなAPIワークフローは、テキストエディタとCLIだけでも実行できます。一方で、多くのチームはGitを信頼できる情報源にしたまま、GUIで設計したいと考えます。
ApidogのSpec-Firstモードは、そのための選択肢です。OpenAPIファイルをGitリポジトリに保持しながら、ビジュアルデザイナーやエディタで契約を編集できます。編集内容はリポジトリ内のファイルと同期されるため、ブランチ、PR、履歴、レビューの流れを維持できます。
セットアップの詳細は、Spec-Firstモードのドキュメントを参照してください。
重要なのは、ツールそのものではありません。リポジトリを唯一の信頼できる情報源にし、GUIはそのビューとして使うことです。
FAQ
GitネイティブAPIデザインはOpenAPI専用ですか?
いいえ。テキストベースの契約フォーマットであれば同じ考え方を適用できます。
例:
- OpenAPI
- AsyncAPI
- gRPC の
.proto - GraphQL SDL
契約がテキストファイルで、差分、ブランチ、レビューが可能であれば、Gitネイティブに扱えます。
Gitネイティブワークフローで破壊的変更をどう扱いますか?
破壊的変更は、明示的に扱います。
実践例:
-
break/api-ブランチを使う - メジャーバージョンを上げる
-
CODEOWNERSで管理者承認を必須にする - 可能なら新旧形式を並行提供する
- 古いパスやフィールドには非推奨期間を設ける
-
CHANGELOG.mdに影響範囲を書く
PRの差分、バージョン番号、変更履歴を組み合わせて、コンシューマに変更を伝えます。
API仕様はコードと同じリポジトリに置くべきですか?
通常、同じチームが仕様と実装を所有しているなら、同じリポジトリに置くのが簡単です。
メリット:
- 契約と実装を同じPRで変更できる
- CIで契約テストを実行しやすい
- バージョンの対応関係が明確になる
一方、多数のチームが同じAPI仕様を共有し、独立したリリース管理が必要な場合は、仕様専用リポジトリを検討します。
仕様とコードが乖離するのを防ぐにはどうすればよいですか?
CIで契約テストを実行します。実行中のサーバーにリクエストを送り、コミット済み仕様に対してレスポンスを検証します。
さらに、次の運用を組み合わせます。
- スタブを仕様から生成する
- クライアントを仕様から生成する
- ドキュメントを仕様から生成する
- 仕様変更PRにレビューを必須にする
- lintと契約テストをPRごとに実行する
乖離を本番バグではなく、CIの失敗として検出するのがポイントです。
結論
GitネイティブAPIデザインは、製品ではなく開発規律です。API契約をソースコードとして扱い、ブランチで変更し、PRでレビューし、コミット済み仕様からモック、テスト、クライアント、ドキュメントを生成します。
小さく始めるなら、次の順序がおすすめです。
- 仕様をリポジトリに置く
- API変更をPRレビュー必須にする
-
CODEOWNERSを設定する - CIで仕様リンティングを実行する
- モックとドキュメントを仕様から生成する
- 契約テストをCIに追加する
このワークフローを続けると、Git履歴がAPI履歴になります。誰が、いつ、なぜ契約を変更したのかを追跡でき、設計レビューも実装前に行えます。
Gitに仕様を保持しながらビジュアルに設計したい場合は、ApidogのSpec-Firstモードを試し、双方向同期がこのワークフローにどう組み込めるか確認してください。


Top comments (0)