APIに新機能を追加したいが、既存のクライアントを壊したくない——APIを長期運用する上で、バージョニング戦略の設計は避けて通れない課題です。適切な戦略なしにAPIを変更すると、連携先のシステムが突然動かなくなる深刻な事態を招きます。
本記事では、APIバージョニングの主要な方式の比較から、破壊的変更の定義、バージョン移行戦略、廃止プロセスの設計まで実践的に解説します。
APIバージョニングが必要な理由
なぜAPIにバージョニングが必要なのか、その背景を理解しましょう。
APIは契約である
APIは、サーバー(提供者)とクライアント(利用者)の間の「契約」です。クライアントは「このエンドポイントにこの形式でリクエストすれば、この形式のレスポンスが返ってくる」という前提でコードを書いています。この契約を一方的に変更すれば、クライアント側のシステムが破綻します。
破壊的変更とは何か
APIの変更には「破壊的変更(Breaking Change)」と「非破壊的変更(Non-Breaking Change)」があります。
破壊的変更の例
- エンドポイントのURLを変更する
- 必須パラメータを追加する
- レスポンスのフィールドを削除・名前変更する
- レスポンスのデータ型を変更する(string → integer など)
- HTTPステータスコードの意味を変更する
- 認証方式を変更する
- エラーレスポンスの形式を変更する
非破壊的変更の例
- オプショナルなパラメータを追加する
- レスポンスに新しいフィールドを追加する
- 新しいエンドポイントを追加する
- エンドポイントの内部実装を変更する(外部仕様が同じであれば)
- パフォーマンスの改善
バージョニングが必要なのは、破壊的変更を安全に導入するためです。非破壊的変更であれば、バージョンを上げずに既存のAPIに追加できます。
バージョニングを避ける努力
バージョニングはコストがかかるため、まずはバージョニングを避ける設計を心がけましょう。
拡張可能な設計
最初からレスポンスにメタデータフィールドを用意する、フィールド名を汎用的にするなど、将来の変更に対応しやすい設計を行います。
Tolerant Reader パターン
クライアント側で「知らないフィールドは無視する」というルールを徹底します。サーバーが新しいフィールドを追加しても、クライアントが壊れません。
Robustness Principle(ポステルの法則)
「送信するものは厳密に、受信するものは寛容に」という原則です。サーバーは柔軟にリクエストを受け入れ、クライアントは柔軟にレスポンスを処理します。
バージョニングの主要方式を比較する
APIバージョニングには主に3つの方式があります。それぞれの特徴を詳しく見ていきましょう。
URLパスバージョニング
最も広く使われている方式で、URLのパスにバージョン番号を含めます。
# URLパスバージョニングの例
GET https://api.example.com/v1/users
GET https://api.example.com/v2/users
POST https://api.example.com/v1/users
POST https://api.example.com/v2/users
メリット
- 最も直感的で理解しやすい
- URLを見るだけでバージョンがわかる
- ブラウザのアドレスバーやcurlコマンドでの確認が容易
- APIゲートウェイでのルーティングが簡単
- キャッシュが容易(URLが異なるため)
デメリット
- RESTの原則(URIはリソースを識別する)に厳密には違反する
- バージョンが変わるとURLが変わるため、すべてのクライアントがURLを更新する必要がある
- バージョンごとにルーティング設定が必要
採用企業:GitHub API、Google Maps API、Twitter API、Stripe APIなど
HTTPヘッダーバージョニング
カスタムHTTPヘッダーでバージョンを指定する方式です。
# HTTPヘッダーバージョニングの例
GET https://api.example.com/users
Accept: application/vnd.example.v2+json
# または独自ヘッダー
GET https://api.example.com/users
X-API-Version: 2
メリット
- URLがクリーンに保たれる(リソースの識別に専念)
- RESTの原則に沿っている
- コンテントネゴシエーションの仕組みを活用できる
デメリット
- ブラウザのアドレスバーやリンクだけではバージョンがわからない
- curlコマンドでの動作確認に毎回ヘッダー指定が必要
- HTTPキャッシュの設定が複雑になる(Varyヘッダーの設定が必要)
- APIゲートウェイの設定が複雑になる場合がある
採用企業:GitHub API(Accept ヘッダーも併用)
クエリパラメータバージョニング
クエリパラメータでバージョンを指定する方式です。
# クエリパラメータバージョニングの例
GET https://api.example.com/users?version=2
GET https://api.example.com/users?api-version=2026-03-01
メリット
- バージョン省略時にデフォルトバージョンを適用できる
- 既存のURLを変更せずにバージョニングを導入できる
- テスト時にパラメータを変えるだけで異なるバージョンを試せる
デメリット
- クエリパラメータが長くなり、URLが煩雑になる
- バージョンパラメータがビジネスロジックのパラメータと混在する
- URLパスバージョニングほど一般的ではない
採用企業:Amazon Web Services API、Microsoft Azure API(日付ベース)
方式の選定ガイドライン
迷ったらURLパスバージョニングを選ぶのが無難です。理由は以下のとおりです。
- 業界で最も広く採用されており、開発者にとって馴染みがある
- 実装とテストが容易
- APIゲートウェイやCDNとの相性が良い
- デバッグが容易(URLを見るだけでバージョンがわかる)
バージョン番号の設計
バージョン番号の付け方にもいくつかの方式があります。
メジャーバージョンのみ
最もシンプルで、破壊的変更がある場合にのみバージョンを上げます。
# v1, v2, v3 のように管理
/v1/users → 初期バージョン
/v2/users → 破壊的変更を含む新バージョン
非破壊的変更は既存バージョン内で追加するため、バージョン番号が頻繁に変わることはありません。多くのAPIではメジャーバージョンがv1からv3程度に留まるのが理想です。バージョン番号が大きくなるほど、クライアントの移行負担が増大します。
日付ベースのバージョニング
Stripeが採用している方式で、APIバージョンを日付で管理します。
# Stripeのバージョニング例
Stripe-Version: 2026-03-01
# curlでの指定
curl https://api.stripe.com/v1/charges \
-H "Stripe-Version: 2026-03-01" \
-H "Authorization: Bearer sk_test_..."
この方式では、各クライアントが登録時のAPIバージョンに固定され、明示的にバージョンを更新しない限り動作が変わりません。日付で管理することで、変更の時系列が把握しやすくなります。
セマンティックバージョニングとの関係
セマンティックバージョニング(SemVer: MAJOR.MINOR.PATCH)はライブラリのバージョニングには適していますが、APIのURLバージョニングにはメジャーバージョンのみを使うのが一般的です。マイナーバージョンやパッチバージョンはAPI内部で管理し、クライアントには見せません。
バージョン共存のアーキテクチャ設計
複数のAPIバージョンを同時に運用するためのアーキテクチャパターンを紹介します。
ルーティング層でのバージョン分岐
// Express.jsでのルーティングによるバージョン管理
import express from 'express';
import v1Router from './routes/v1';
import v2Router from './routes/v2';
const app = express();
// バージョンごとにルーターを分離
app.use('/v1', v1Router);
app.use('/v2', v2Router);
// デフォルトバージョンへのリダイレクト
app.use('/users', (req, res) => {
res.redirect(301, `/v2${req.url}`);
});
// routes/v1/users.ts
import { Router } from 'express';
const router = Router();
router.get('/users', async (req, res) => {
const users = await userService.getAll();
// v1のレスポンス形式
res.json(users.map(u => ({
id: u.id,
name: u.name,
email: u.email,
})));
});
export default router;
// routes/v2/users.ts
import { Router } from 'express';
const router = Router();
router.get('/users', async (req, res) => {
const users = await userService.getAll();
// v2のレスポンス形式(ページネーション追加、フィールド変更)
res.json({
data: users.map(u => ({
id: u.id,
fullName: u.name, // name → fullName に変更
emailAddress: u.email, // email → emailAddress に変更
role: u.role, // 新フィールド追加
createdAt: u.createdAt,
})),
pagination: {
page: 1,
totalPages: 10,
totalCount: 195,
},
});
});
export default router;
コントローラー層でのバージョン分岐
共通のビジネスロジック(サービス層)を共有し、レスポンスの変換のみをバージョンごとに分けるパターンです。
// アダプターパターンでバージョン差分を吸収
interface UserResponseAdapter {
transform(user: UserEntity): object;
}
class UserResponseV1 implements UserResponseAdapter {
transform(user: UserEntity) {
return {
id: user.id,
name: user.name,
email: user.email,
};
}
}
class UserResponseV2 implements UserResponseAdapter {
transform(user: UserEntity) {
return {
id: user.id,
fullName: user.name,
emailAddress: user.email,
role: user.role,
createdAt: user.createdAt,
};
}
}
// バージョンに応じてアダプターを選択
function getAdapter(version: string): UserResponseAdapter {
switch (version) {
case 'v1': return new UserResponseV1();
case 'v2': return new UserResponseV2();
default: return new UserResponseV2();
}
}
このアプローチでは、ビジネスロジックの重複を避けつつ、バージョンごとのレスポンス差分を明確に管理できます。
APIゲートウェイでのバージョンルーティング
# Nginx でのバージョンルーティング
upstream api_v1 {
server v1-service:3000;
}
upstream api_v2 {
server v2-service:3000;
}
server {
location /v1/ {
proxy_pass http://api_v1/;
}
location /v2/ {
proxy_pass http://api_v2/;
}
# デフォルトは最新バージョンへ
location /api/ {
proxy_pass http://api_v2/;
}
}
非推奨化と廃止のプロセス
古いバージョンを安全に廃止するためのプロセス設計は、バージョニング戦略の重要な一部です。
非推奨化(Deprecation)のステップ
ステップ1:告知期間(3〜6ヶ月前)
ドキュメント、API changelog、メール通知でバージョン廃止の予定を告知します。
# 非推奨ヘッダーの付与
HTTP/1.1 200 OK
Deprecation: Sun, 27 Sep 2026 00:00:00 GMT
Sunset: Mon, 27 Mar 2027 00:00:00 GMT
Link: <https://api.example.com/v2/users>; rel="successor-version"
ステップ2:移行支援期間
移行ガイドを提供し、v1からv2への変更点と対応方法を文書化します。
# 移行ガイドの例(CHANGELOG.md)
## v2への移行ガイド
### 破壊的変更
- `GET /v1/users` のレスポンス形式が変更されました
- `name` → `fullName` に名称変更
- `email` → `emailAddress` に名称変更
- `role` フィールドが追加されました
- レスポンスが `{ data: [], pagination: {} }` 形式に変更
### 移行手順
1. クライアントコードの `name` を `fullName` に変更
2. クライアントコードの `email` を `emailAddress` に変更
3. ページネーション対応のため、レスポンス処理を `response.data` に変更
ステップ3:利用状況の監視
廃止予定のバージョンのリクエスト数を監視し、移行が進んでいないクライアントに個別に連絡します。
// 非推奨バージョンの利用状況を記録するミドルウェア
function deprecationTracker(req, res, next) {
const apiKey = req.headers['x-api-key'];
const version = req.baseUrl.match(/\/v(\d+)/)?.[1];
if (version === '1') {
// 利用状況をログに記録
logger.warn('非推奨APIバージョンの利用', {
apiKey,
version,
endpoint: req.path,
ip: req.ip,
});
// 非推奨ヘッダーを付与
res.set('Deprecation', 'true');
res.set('Sunset', 'Mon, 27 Mar 2027 00:00:00 GMT');
}
next();
}
ステップ4:廃止(Sunset)
告知期間を経て、旧バージョンを廃止します。即座に404を返すのではなく、まずは410 Gone で「このバージョンは廃止された」ことを明示するレスポンスを返します。
// 廃止済みバージョンのハンドリング
app.use('/v1', (req, res) => {
res.status(410).json({
error: 'API_VERSION_SUNSET',
message: 'v1 APIは2027年3月27日をもって廃止されました。v2をご利用ください。',
migrationGuide: 'https://docs.example.com/migration/v1-to-v2',
currentVersion: 'https://api.example.com/v2',
});
});
バージョニング戦略のベストプラクティス
最後に、APIバージョニングの全体的なベストプラクティスをまとめます。
設計段階のベストプラクティス
バージョン変更を最小限にする設計
最初のAPI設計時に拡張性を考慮し、破壊的変更の必要性を減らします。レスポンスフィールドは追加可能な構造にしておきます。
同時に運用するバージョンは2つまで
3つ以上のバージョンの同時運用は、保守コストが急激に増大します。新バージョンをリリースしたら、最も古いバージョンの廃止を計画します。
変更ログの維持
すべてのAPI変更を日付付きで記録します。変更ログは、クライアント開発者が移行計画を立てるための重要な情報源です。
運用段階のベストプラクティス
十分な移行期間の確保
最低3ヶ月、理想的には6ヶ月以上の移行期間を設けます。エンタープライズ向けAPIではさらに長い期間が必要な場合があります。
バージョン別のメトリクス監視
各バージョンのリクエスト数、エラー率、レイテンシを監視し、移行の進捗とサービス品質を把握します。
APIバージョニングポリシーの明文化
バージョニングのルール(いつ新バージョンを作るか、非推奨化の期間はどれくらいか)をポリシーとして明文化し、クライアント開発者に公開します。
まとめ
APIバージョニングは、長期的なAPI運用の安定性を確保するための重要な設計判断です。本記事のポイントを振り返りましょう。
まずは避ける努力を
拡張可能な設計とTolerant Readerパターンにより、破壊的変更の必要性自体を減らすことが最善策です。
方式の選択
迷ったらURLパスバージョニング(/v1/users)を選びましょう。業界で最も広く採用されており、実装・テスト・デバッグが容易です。
バージョンは少なく
同時運用するバージョンは2つまでに抑え、メジャーバージョンの数もできるだけ少なくする設計を心がけましょう。
廃止プロセスの設計
告知、移行支援、監視、廃止という段階的なプロセスを事前に設計しておくことで、スムーズなバージョン移行を実現できます。
バージョニング戦略は一度決めると変更が困難です。API設計の初期段階でチーム内で方針を合意し、ドキュメント化しておくことを強くおすすめします。
関連記事
AIエージェント開発入門|自律型AIの仕組みと構築方法を解説【2026年版】
AI駆動コーディングワークフロー|Claude Code・Cursor・Copilotの実践的使い分け
プロンプトエンジニアリング上級編|Chain-of-Thought・Few-Shot・ReActの実践
APIレート制限の設計と実装|トークンバケット・スライディングウィンドウ解説
BIツール入門|Metabase・Redash・Looker Studioでデータ可視化する方法
チャットボット開発入門|LINE Bot・Slack Botの構築方法と活用事例
CI/CDパイプラインの基礎|継続的インテグレーション・デリバリーの全体像
クリーンコードの原則|可読性・保守性を高める7つの実践ルール