11
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

APIのバージョニングで揉めない:互換性ポリシーと実装テンプレ

Last updated at Posted at 2025-12-25

はじめに

APIのバージョニングは「技術」より「合意形成」で失敗しがちです。
v1 v2 の数字を付けるかどうかよりも

  • 互換性をどこまで守るのか
  • 何を「破壊的変更」と見なすのか
  • 変更の通知と移行期間をどう運用するのか

が曖昧だと、結局は毎回揉めてスピードが落ちます。

この記事は、バージョニング手法の紹介ではなく
チームで合意できる互換性ポリシーと、すぐ使えるテンプレをまとめます。

よくある失敗パターン

  • 「とりあえず v2」で逃げるが、v1が永遠に残る
  • v1とv2で仕様の差分が曖昧で、クライアントが移行できない
  • 破壊的変更の定義がなく、レビューで毎回議論が再発する
  • URLバージョンとヘッダバージョンが混在して、運用が破綻する

まず決めること 互換性ポリシー

互換性の前提を分類する

まずクライアントの性質で期待値が変わります。

  • 単一フロントで同時デプロイできる
  • モバイルが含まれ更新が遅い
  • 外部提供で、更新時期が制御できない

後ろに行くほど「破壊しない設計」と「長い移行期間」が必要です。

破壊的変更の定義を固定する

チーム内で、以下を破壊的変更として扱うか決めます。

  • レスポンスフィールドの削除
  • レスポンスフィールドの型変更
  • 必須入力の追加
  • 列挙値の削除
  • HTTPステータスやエラーコードの意味変更

逆に「非破壊」扱いでも、クライアント実装によっては壊れます。
たとえばフィールド追加は一般に安全ですが

  • 厳格なスキーマバリデーション
  • 未知フィールドをエラーにするクライアント

があると破壊になります。
その場合は「クライアントの実装規約」側で吸収するべきです。

バージョニング手法の選び方

SemVer(Semantic Versioning)をAPIにどう適用するか

SemVerは本来「ソフトウェアのリリース番号」の約束事ですが、API運用にもそのまま流用できます。
重要なのは「番号の付け方」よりも、

  • 何を破壊的変更(= MAJOR)と見なすか
  • 破壊的変更を出すまでの移行/告知をどうするか

をチームで固定できる点です。

基本ルール(X.Y.Z)

  • MAJOR(X): 破壊的変更を含む
  • MINOR(Y): 後方互換のある機能追加
  • PATCH(Z): 後方互換のあるバグ修正

「APIはURLにv1/v2を付けるか?」とは独立の話です。
例えばURLは /api/v1 のままでも、内部の契約(スキーマ/仕様)には 1.7.3 のようなSemVerを割り当てて運用できます。

APIにおけるMAJOR/MINOR/PATCHの読み替え例

  • MAJOR
    • レスポンスフィールドの削除
    • レスポンスフィールドの型変更
    • 必須入力の追加(サーバー側でデフォルト補完できない)
    • エラーコード/HTTPステータスの意味変更
    • 列挙値の削除(クライアントにunknown許容がない場合)
  • MINOR
    • 任意フィールドの追加(クライアントが未知フィールド許容の前提)
    • 列挙値の追加(クライアントがunknown許容の前提)
    • 新エンドポイント追加(既存に影響なし)
  • PATCH
    • 仕様の明確化(ドキュメントの誤記修正)
    • バグ修正(契約を変えない範囲)

ポイントは「フィールド追加は常にMINORで安全」と思い込まないことです。
未知フィールドで落ちるクライアントが存在するなら、それはあなたの互換性ポリシーではMAJOR扱いになります。

MAJORを出す前の運用(deprecate期間をSemVerに組み込む)

破壊的変更は、いきなりMAJORで切るより

  1. 旧要素を deprecated として残す(MINORで追加/告知)
  2. 移行期間を確保(例: 90日)
  3. 期限到来で削除(MAJORで削除)

の順にすると揉めにくいです。

0.y.z(v0系)をどう扱うか

SemVerでは 0.y.z は「互換性を保証しない」扱いです。
ただしAPIでこれをそのままやると運用が事故りやすいので、

  • 外部提供やモバイルが絡むAPIは、原則 1.0.0 から開始
  • 0.y.z を許すなら「どの範囲は壊して良いか」を別途明文化

のどちらかをおすすめします。

URLにバージョンを入れる

  • /api/v1/users

向いている

  • 外部提供で分かりやすさが最優先
  • キャッシュやログでバージョンを一目で追いたい

注意

  • vが増えるほどエンドポイントが増殖しやすい
  • v跨ぎの共通化が難しくなる

ヘッダでバージョンを指定する

  • Accept: application/vnd.example.v1+json

向いている

  • URLを安定させたい
  • バージョンをメディアタイプとして扱いたい

注意

  • ブラウザやデバッグ時の見えにくさ
  • キャッシュ層でヘッダを考慮する必要

クエリで指定する

  • /users?api_version=1

注意

  • 通常はおすすめしません
  • キャッシュや仕様の一貫性が崩れやすい

まずはこれで進める実務テンプレ

テンプレ 互換性ポリシー文書

以下をそのまま README やADRに貼って埋めると、議論が早く終わります。

  • 対象API
  • サポートするクライアント種別
  • 非破壊変更の定義
  • 破壊的変更の定義
  • 互換性の保証期間
  • 廃止告知の手段
  • 移行期間の最小日数
  • v1終了の基準

SemVerを採用する場合は、追加で以下も埋めると議論が止まります。

  • バージョン表記(例: X.Y.Z / 日付 / その他)
  • MAJOR/MINOR/PATCHの判定基準(破壊的変更の定義との対応)
  • deprecatedの通知方法と最短維持期間(例: 90日 or 2 MINORリリース)
  • 「0.y.z」を使うか(使うなら互換性期待値)

テンプレ 破壊的変更チェックリスト(PR用)

まず、この変更がSemVerでどれに該当するかを明記

  • PATCH / MINOR / MAJOR のどれかを書いた

  • フィールド削除がない

  • フィールド型変更がない

  • 必須入力の追加がない

  • 列挙値の削除がない

  • エラーコードの意味変更がない

  • 既存クライアントが未知フィールドを許容する

  • 変更点がドキュメントに反映されている

  • 移行手順がある

MAJOR相当の場合

  • deprecated期間(移行猶予日数/期限)が明記されている
  • 期限到来後の削除計画(いつ/どう消すか)がある

テンプレ 非互換を避ける設計パターン

フィールド削除の代わりに deprecated

  • すぐ消すのではなく deprecated として残し
  • 一定期間後に削除する

必須入力追加の代わりにデフォルト適用

  • 直ちに必須化せず
  • サーバー側でデフォルトを補う
  • 次バージョンで必須化の準備をする

列挙値の進化

  • 列挙に新しい値を追加する前提で
  • クライアントは unknown を許容する

運用の落とし穴

v1とv2が長期併存して止まる

原因は「v1終了条件」がないことが多いです。

  • ある割合以上のクライアントが移行
  • ある日付までに移行
  • 主要顧客の移行完了

など、終了条件を最初から決めます。

ドキュメントが追随せず、実装が真実になる

  • 変更のたびに差分を書く
  • 仕様の例(リクエスト/レスポンス)を更新する

これをPRの必須チェックに入れるのが一番効きます。

まとめ

APIバージョニングで揉めないコツは
手法選びより先に、互換性ポリシーと運用ルールを固定することです。
テンプレを埋めて合意形成のコストを下げ
破壊的変更をレビューで機械的に検知できる状態を作ると、長期的に効きます。

11
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?