目次
- APIバージョニングが必要な理由
- APIは契約である
- 破壊的変更とは何か
- バージョニングを避ける努力
- バージョニングの主要方式を比較する
- URLパスバージョニング
- HTTPヘッダーバージョニング
- クエリパラメータバージョニング
- 方式の選定ガイドライン
- バージョン番号の設計
- メジャーバージョンのみ
- 日付ベースのバージョニング
- セマンティックバージョニングとの関係
- バージョン共存のアーキテクチャ設計
- ルーティング層でのバージョン分岐
- コントローラー層でのバージョン分岐
- APIゲートウェイでのバージョンルーティング
- 非推奨化と廃止のプロセス
- 非推奨化(Deprecation)のステップ
- バージョニング戦略のベストプラクティス
- 設計段階のベストプラクティス
- 運用段階のベストプラクティス
- まとめ
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設計の初期段階でチーム内で方針を合意し、ドキュメント化しておくことを強くおすすめします。
先行モニター企業 募集中|先着5社・2026年11月末まで 生成AIの利用費、「誰が・何のために・いくら」まで見えていますか?
株式会社カイダンと共同開発したAI利用ガバナンスSaaS「ManageAI」は、OpenAI・Azure OpenAI・Claude・AWS Bedrock・Google Vertex AIの費用と利用状況を、部署・利用者・プロジェクト別に可視化します。導入は読み取り専用キーの登録だけ。初期費用0円・月額5万円(税別)で先行モニター企業を募集しています。
ニュースリリースを読む関連記事
Related / 9 articles
Notes & Insights
- プログラミング
DDoS攻撃の仕組みと対策入門|レイヤー別の防御とCDN・クラウドの活用
DDoS攻撃をボリューム型・プロトコル型・アプリ層に分けて仕組みを解説し、自前サーバーで防げない理由、CloudflareやAWS Shieldの標準防御、オリジンIPの隠し方、レートリミットとBot対策、攻撃を受けたときの初動、費用が跳ね上がるDenial of Walletへの備えまでわかります。
- プログラミング
WAFとは?仕組み・導入パターン・誤検知対策|Webアプリを攻撃から守る実践ガイド
WAFがファイアウォールやIDSと何が違うのか、シグネチャとマネージドルールの仕組み、Cloudflare WAF・AWS WAF・ModSecurityの比較、フォーム送信がブロックされる誤検知の調査と例外設定、ログ監視、WAFが代替できないことまで実践的に解説します。
- プログラミング
セキュリティヘッダー入門|CSP・HSTS・X-Frame-Optionsの設定と効果を実践解説
CSP・HSTS・X-Frame-Options・X-Content-Type-Optionsなど主要セキュリティヘッダーが防ぐ攻撃と、CSPのReport-Onlyからの段階導入、nonce/hash、HSTS preloadの不可逆リスク、Nginx・Next.js・Astroでの設定例、確認方法を解説します。
- プログラミング
クラウドの通信費(Egress)入門|データ転送量課金の仕組みと転送コストを抑える設計
クラウドの「受信無料・送信有料」の原則、AZ間・リージョン間・インターネット向けの単価差、NATゲートウェイ処理料の罠、CDNで転送量を減らす方法、バックアップやログ転送の見落とし、請求書で転送料を特定する手順を解説。想定外の請求を防げます。
- プログラミング
秘密情報をGitに入れない仕組み|.gitignore・git-secrets・履歴から漏れた鍵の削除
APIキーや.envをGitにコミットしてしまう典型経路と、.gitignore・.env.exampleの運用、pre-commitでのgitleaks検知、GitHub secret scanningの活用、漏れた鍵の無効化と履歴書き換え(git filter-repo)の手順を解説。仕組みで再発を防げます。
- プログラミング
開発・ステージング・本番環境の分離設計|環境差分をなくす構成とアクセス制御
開発・ステージング・本番それぞれの目的と、構成をコードで揃える方法、環境別の設定注入、本番データを使わないテストデータ戦略、ステージングの保護(Basic認証・IP制限・noindex)、コストを抑える運用までを解説。環境差分による本番障害を防げます。
- プログラミング
ngrok・Cloudflare Tunnelでローカルを公開|Webhook開発とデモ環境の作り方
NAT内のローカル環境にStripeやLINEのWebhookを届けるトンネリングの仕組みを解説。ngrok・Cloudflare Tunnel・localtunnelの比較、固定ドメインと認証、リクエスト検査、公開時のセキュリティ、自宅サーバー公開への応用までわかります。
- プログラミング
ローカル開発環境のHTTPS化|mkcert・hostsファイル・自己署名証明書の正しい使い方
ローカル開発をHTTPS前提にすべき理由(Secure Cookie・Service Worker・OAuth)と、mkcertでローカルCAを作りhostsで独自ドメインを割り当ててVite・Next.js・Dockerで使う手順を解説。証明書警告を無視する癖の危険も理解できます。
- プログラミング
localhost・0.0.0.0・127.0.0.1の違い|ポートとUnixソケットを理解して「つながらない」を解決
localhost・127.0.0.1・0.0.0.0の意味の違い、Dockerで外から接続できない原因、host.docker.internal、ポート競合の調べ方、Unixソケットの利点と権限、1024未満ポートの制約を解説。「つながらない」を仕組みから解決できます。
先行モニター企業 募集中
生成AIのコストを「部署別」に、請求書より先に。
先着5社限定・2026年11月末まで。初期費用0円・月額5万円(税別)で、正式版と同等の機能に加え、開発者と伴走者による導入支援を追加費用なしで提供します。プロンプト原文は一切取得しません。
株式会社カイダン × Harmonic Society株式会社の共同事業|読み取り専用キーの登録だけで導入できます