同じルートやバージョンを維持しているだけでは、APIに互換性があるとはいえません。利用者はデータの構造、バリデーション規則、デフォルト値、エラー時の挙動にも依存します。クライアントごとに更新のタイミングが異なる場合、サーバーの保守担当者には小さな変更に見えても、モバイルアプリ、サードパーティ連携、社内プロセスを中断させることがあります。
PHP APIのデータ互換性ポリシーを定めれば、どの変更を許容するか、どうデプロイするか、契約を終了する前にどのテストを通過すべきかを明確にできます。あらゆる変更に適用できる万能な互換性ルールはありません。各利用者がデータをどう読み取り、送信するかを考慮する必要があります。
契約にはデータ、バリデーション、挙動が含まれる

API契約は、文書化されたスキーマだけにとどまりません。フィールドとその型、省略やnullが許されるか、日付や金額の解釈、リクエストで受け付ける値、エラー形式、レスポンスに関する保証も含みます。クライアントが依存している場合は、コレクションの順序や識別子の安定性など、観測可能な規則も対象です。
PHPでは、データ転送オブジェクト、バリデータ、シリアライザが、契約の一部を具体化することがよくあります。コントローラだけを確認しても、バリデーション規則、レスポンスリソース、モデルとAPIのマッピングに潜む互換性のない変更を見落とすおそれがあります。クラスやテーブルの内部構造ではなく、クライアントが実際に観測する内容に基づいて契約を文書化しましょう。
利用者に応じて変更を分類する
分類は評価のための手段であり、自動的に互換性を保証するものではありません。追加的な変更は、未知のフィールドを無視するクライアントなら通常は動作を維持できますが、レスポンスを厳密な構造に変換するクライアントや、閉じたスキーマに照らして検証するクライアントを壊すことがあります。同様に、リクエストに新しい任意フィールドを加えることは古いクライアントに無害でも、それを必須にすれば問題になり得ます。
- 通常は追加的:リクエストやレスポンスに任意フィールドを加える、またはコレクションに値を追加する。ただし、利用者がそうした要素を許容することが前提です。
- 互換性を損なう可能性がある:フィールドの削除や名前変更、型の変更、任意フィールドの必須化、エラー形式の変更、既存の値の意味の変更。
- 状況に依存する:順序、数値精度、タイムゾーン、状態の意味、ページネーション条件の変更。スキーマが変わらなくても、クライアントにとって結果が変わることがあります。
変更を承認する前に、利用者を特定し、データの処理方法を確認してください。未知のフィールドは無視される場合もあれば、バリデーションエラーを引き起こしたり、想定外のロジックに渡されたりする場合もあります。言語、ライブラリ、クライアントのバージョンによって反応が同じだと決めつけないでください。
リクエストとレスポンスは慎重に進化させる
レスポンスへのフィールド追加は、余分なプロパティを拒否する厳格なクライアントが存在する可能性を考慮すれば、より安全に行えます。フィールドの意味や型が変わる場合、黙って再利用してはいけません。意味が明確な新しいフィールドを追加し、旧フィールドとの関係を文書化したうえで、定めた移行期間中は両方を維持してください。
リクエストでは、キーの欠落、null、空の値を区別することが不可欠です。PHPでキーの欠落を値nullと同じように扱うバリデーションは、データを消去したり、予期しないデフォルト値を適用したりするおそれがあります。それぞれのケースの意味を定義し、新旧両方のクライアントをテストしてください。新しいフィールドについては、最初のデプロイから必須にするのではなく、当初は欠落を許容し、互換性のある動作を割り当てることを検討しましょう。
ルートのバージョン管理だけが選択肢ではありません。変更に互換性があればルートを維持したまま契約を進化させられます。互換性がなく、運用上も併存させる意義がある場合は、新しいバージョンを公開できます。いずれの場合も、サポートポリシーを文書化してください。バージョンラベルだけでは、契約がいつまで利用できるかは伝わりません。
データベースとAPIを段階的にデプロイする
安全なデプロイでは、ストレージの変更と新しい挙動の公開を分けます。一般的な手順は、スキーマを拡張し、旧構造と新構造の両方で動作するコードをデプロイし、必要に応じてデータを移行してから、新しい読み取りや書き込みを有効にすることです。古いカラムや経路の削除は、不要になったことを示す十分な根拠が得られてから行います。
この拡張・縮小アプローチにより、まだ存在しないカラムをアプリケーションのバージョンが前提にしたり、新しいデプロイによって古いプロセスが動かなくなったりする事態を避けられます。複数のインスタンスやバックグラウンドワーカーがあるシステムでは、デプロイ中に異なるコードバージョンが共存する可能性を考慮してください。マイグレーションはその共存に対応し、各段階が失敗した場合の復旧戦略も備える必要があります。
段階的な公開――たとえば、管理された一部の利用者に機能を有効化すること――は影響を抑えられますが、一般公開とは異なり、互換性の代わりにもなりません。挙動の観測とロールバックに役立つ場合は有効化制御を使い、拡大を停止する条件をあらかじめ定めてください。
機密データを記録せずに利用状況を測る
どの利用者がまだ契約を使っているか把握するには、個人情報、認証情報、商用データを含むリクエストやレスポンスの本文を保存せずに、対象のバージョンや機能を特定できるテレメトリーが必要です。ルート、申告されたクライアントバージョン、結果、日時など、必要最小限のシグナルを記録し、運用上の必要性と適用される義務に応じてアクセスと保存期間を制限してください。
判断に役立つシグナルを選びましょう。実ユーザーのリクエストと、テスト、再試行、自動化されたトラフィックを区別し、エラー、レイテンシ、トラフィック量の変化も観察してください。信頼できるクライアント識別子がない場合、機密データからその利用者を推測してはいけません。プロキシ、共有キー、バージョンを送信しないクライアントによって、把握できない範囲が残ることも認識してください。
検証可能な基準で契約を終了する
告知した期間が過ぎたという理由だけでバージョンを終了しないでください。リスクに応じたシグナルとしきい値を定めます。たとえば、特定可能なトラフィックが継続的にないこと、既知の連携の移行が確認できていること、後継バージョンが安定していること、例外に対応するサポート手順があることなどです。不明なトラフィックが続いている場合、識別できないことを未使用の証拠とみなす前に調査してください。
変更内容、影響を受ける対象、代替手段、予定日、移行のテスト方法を事前に伝えてください。利用者側のチームが参照しやすいドキュメントに情報を掲載し、互換性の問題を報告する窓口を設けます。影響を迅速にロールバックできない場合は、より長い移行期間や契約の一時的な併存を検討してください。
公開前のチェックリスト

- 影響を受けるフィールド、型、null許容性、デフォルト値、エラーを文書化したか?
- 新しいフィールドや欠落したフィールドに対する、寛容なクライアントと厳格なクライアントの挙動を確認したか?
- 契約テストで、既知の利用者とバリデーションの境界ケースを網羅しているか?
- データベースマイグレーションは、古いアプリケーションバージョンとの共存を可能にしているか?
- 機密データを取得せずにエラーと契約の利用状況を検出できるだけのメトリクスがあるか?
- 担当者、告知、ロールバック基準、旧仕様を終了する条件を定めたか?
有効なポリシーは、どの変更もどのクライアントも壊さないと約束するものではありません。前提を明確にし、予期せぬ事態を減らし、根拠に基づいて行動できるようにします。契約を変更するたびに判断を見直してください。特に、チームが更新サイクルを管理できない外部利用者がいるAPIでは重要です。



