
API設計の原則と拡張性確保
事業要件から逆算する「契約」としてのAPI
APIは実装の詳細ではなく「契約」です。契約は頻繁に変えない前提で、将来の拡張を前提に設計します。最初に決めるのは技術ではなく、ユースケースと変更コストです。誰が、いつ、どの操作を、どの頻度で行い、どの失敗が致命的か。ここを言語化してから次の原則に落とし込みます。
- リソース指向と一貫性: 名詞で表現し、/orders/{id}/items のように階層は浅く。動詞は状態遷移(/orders/{id}: PATCH で status=shipped)に寄せます。
- 同期/非同期の切り分け: 重い処理はジョブキュー化し、受理のみを200系で返し、結果はWebhooksやポーリングで取得。
- 冪等性: POSTでもIdempotency-Keyを受け付け、重複作成を防止。決済・予約・在庫は必須です。
- 標準化したエラー: machine-readableなcode、人間向けmessage、原因のhint、再試行可否、関連ドキュメントURLを返却。
- 権限とスコープ: 最小権限のスコープ設計。監査ログに誰が何をしたかを残す前提でAPIを切る。
- SLO前提の契約: レイテンシ目標(例 p95 < 300ms)、整合性モデル(強い/結果整合)を公開。
拡張性を確保する具体パターン
後方互換の原則とバージョニング
- 「追加はOK、削除・意味変更はNG」を基本に。新規フィールドはオプショナルで、既存レスポンスを壊さない。
- バージョンはURL版(/v1)かヘッダ版(Accept: application/vnd.example.v1+json)。長寿命APIはヘッダ版が移行しやすい。
- 非推奨ポリシー: Deprecation/Sunsetヘッダ、移行ガイド、EOL日程(例 6か月)を明示。v1とv2は一定期間並行稼働。
応答の拡張余地
- エンベロープ: { data, meta, errors } の枠を固定し、metaにページ情報や実験フラグを追加可能に。
- スパースフィールド: fields=price,name のように必要なフィールドのみ取得。無駄な拡張でも既存クライアントが壊れにくい。
- ページングはカーソル型: offsetは遅延や重複に弱い。nextCursor/prevCursorを返却し、安定した並び順と組み合わせる。
- 検索/フィルタの語彙固定: sort=-createdAt、filter[status]=active のようにキーを体系化。
可観測性と信頼性のための仕様
- 相関ID: リクエストID(例 X-Request-Id)を要求/応答で往復。分散トレーシングヘッダ(traceparent)もサポート。
- レート制御: 429時にRetry-Afterを返却。X-RateLimit-Remaining等で利用者が自律的に制御できるように。
- リトライの指針: 冪等エンドポイントのみ再試行可。タイムアウト閾値やバックオフ規則をドキュメント化。
イベント連携の進化可能性
- Webhooksのバージョン管理と署名検証。再送戦略(指数バックオフ、最大再送回数)と順序保証の扱いを明記。
- 「アウトボックス」パターンで整合性を担保。書き込みとイベント公開の原子性を保つ。
スキーマ進化の実務
- OpenAPI/JSON Schemaを単一の真実源に。nullableとoptionalを厳密に区別。
- 列挙型は追加のみ許容。未知値は無視できるようクライアントに指針を提示。
- 将来拡張のためのreservableフィールド(extensions: { … })を許すが、乱用は避ける。
運用で拡張性を腐らせない仕組み
- Contract-first: スキーマからサーバ/SDK/スタブを自動生成。PRでスキーマ差分を機械検出し、破壊的変更をブロック。
- コンシューマ駆動契約テスト: 主要クライアントの期待挙動を契約化し、デプロイ前に検証。
- ドキュメントは実行可能に: サンプルリクエスト、Try-it-out、レート/エラー事例、移行ガイドを常設。
- 段階的リリース: フィーチャーフラグ、カナリア、影トラフィックで互換性を実証。v1/v2の二重書き込み期間を計画。
- 可観測性: p95レイテンシ、5xx率、429発生率、Webhook成功率、依存先のヘルスをダッシュボード化。エラーバジェットで変更速度を調整。
- 鍵・権限制御: テナント別のレートリミットとスコープ。漏洩時のローテーションフローを標準化。
生成AIや開発支援APIの統合では、とくに抽象化が重要です。ChatGPT、Claude、Gemini、Copilotのように提供元ごとにモデル識別子やトークン課金、タイムアウト特性が異なります。モデルIDやプロンプト雛形を構成として外出しし、応答を内部標準に正規化、可重試/不可重試の判定を共通化すると、将来のモデル追加・切替が容易になります。
身近な企業活用例:求人連携APIの再設計で苦情ゼロに
従業員120名規模の人材サービス会社。自社求人データを外部媒体に配信するAPIを社内で急造し、数社のパートナーが利用を開始。しかし、以下の問題が噴出しました。
- ページングがoffset固定で、同期時に抜け・重複が発生。重い時間帯に5xxが増加。
- レスポンスに不要な巨大フィールドが常に含まれ、転送量が増大。
- 仕様変更を口頭で伝達し、互換を壊す更新が発生。パートナー側で障害が連鎖。
- Webhookの署名・再送がなく、一時的な障害でイベントが失われる。
これに対し、3か月で次の改善を実施しました。
- OpenAPIで契約を定義し、スキーマ差分チェックをCIに導入。破壊的変更は自動検知でブロック。
- カーソルページングへ移行し、安定キー(updatedAt,id)で並び順を固定。スパースフィールド指定(fields)を提供。
- ヘッダ版バージョニングとDeprecation/Sunsetヘッダを運用。v1とv2を6か月並行稼働し、移行ガイドを同梱。
- Webhookに署名検証、指数バックオフ、最大再送回数、イベントIDの重複排除を実装。
- Idempotency-Keyを受け付け、求人作成の二重登録を防止。エラーレスポンスにcodeと再試行方針を明記。
結果、同期時の重複・欠落は体感ゼロに近づき、p95レイテンシは40%以上短縮。5xx率は月次で半減し、サポート問い合わせは約3分の1に。新規パートナーの導入期間は平均2週間短縮され、社内チームも仕様変更の心理的コストが大幅に下がりました。とくに「追加はOK、削除・意味変更はNG」という原則と、エンベロープ+スパースフィールドの組み合わせが、拡張余地と安定稼働の両立に効きました。
APIはソフトウェアというより、他社・他部署との長期契約です。仕様の言語化、互換性ポリシー、観測と移行の仕組みを最初に埋め込むことが、将来の速度と信頼を担保します。受託開発ソリューション事業の現場では、要件定義から契約テスト、ドキュメント運用、段階的リリース、EOL管理までを一連のプロセスとして設計・実装・運用に落とし込み、事業の変化に耐えるAPI基盤づくりを支えています。