Aikido

公開API契約の破壊を避ける方法:後方互換性の維持

保守性

ルール

避ける 破る public API 契約を
変更 変更 public API エンドポイント 変更  既存の
既存の クライアント リクエスト である 変更 変更を
考えてみてください 考えて API API 契約  a プロミス  変化する
それを 変更する クライアント 依存  それ 休憩 彼らの コードを

サポート言語: PHP、 Java、 C#、 Python、 JavaScript、 TypeScript

はじめに

Public APIは、サービスとそのコンシューマー間の契約です。クライアントがエンドポイントのリクエスト形式、レスポンス構造、または動作に依存するようになると、それを変更するとクライアントのコードが破損します。破壊的変更はすべてのクライアントに同時更新を強制しますが、クライアントを制御できない場合は多くの場合不可能です。モバイルアプリは強制的に更新できず、サードパーティの統合には移行時間が必要であり、レガシーシステムは更新されない可能性があります。

なぜ重要なのか

クライアントの中断と信頼: 破壊的なAPI変更は、本番クライアントアプリケーションで即座に障害を引き起こします。ユーザーはエラー、データ損失、または完全なサービス停止を経験します。これはAPIプロバイダーとコンシューマー間の信頼を損ない、安定したAPIは安定したままであるという暗黙の契約に違反します。

調整コスト: 複数のクライアントチーム間で破壊的変更を調整することは、コストがかかり、時間がかかります。各チームは、コードの更新、変更のテスト、デプロイに時間を要します。未知のクライアント(モバイルアプリ、サードパーティ統合など)を持つ公開APIの場合、調整は不可能です。

バージョンの乱立: 不適切に管理された破壊的変更は、複数のAPIバージョンを同時に維持することにつながります。各バージョンには個別のコードパス、テスト、ドキュメント、バグ修正が必要であり、メンテナンスの負担が指数関数的に増加します。

コード例

❌ 非準拠:

// Version 1: Original API
app.get('/api/users/:id', async (req, res) => {
    const user = await db.users.findById(req.params.id);
    res.json({ id: user.id, name: user.name });
});

// Version 2: Breaking change - renamed field
app.get('/api/users/:id', async (req, res) => {
    const user = await db.users.findById(req.params.id);
    res.json({
        id: user.id,
        fullName: user.name  // Breaking: 'name' renamed to 'fullName'
    });
});

誤っている理由: name を fullName に変更すると、name フィールドを期待している既存のすべてのクライアントが動作しなくなります。response.name にアクセスするクライアントコードは undefined を受け取り、エラーを引き起こします。この変更により、すべてのクライアントが同時に更新するか、失敗するかのどちらかを強いられます。

✅ 準拠済み:

// Version 2: Additive change - keeps old field, adds new
app.get('/api/users/:id', async (req, res) => {
    const user = await db.users.findById(req.params.id);
    res.json({
        id: user.id,
        name: user.name,           // Keep for backward compatibility
        fullName: user.name        // Add new field (deprecated 'name')
    });
});

// Or use API versioning
app.get('/api/v2/users/:id', async (req, res) => {
    const user = await db.users.findById(req.params.id);
    res.json({ id: user.id, fullName: user.name });
});

これが重要である理由: 古いものを維持する 名前 このフィールドは、機能を追加しながら下位互換性を維持します 氏名 新しいクライアント向け。あるいは、新しいバージョン管理されたエンドポイントを作成する(/api/v2/)は、まだ使用している既存のクライアントに影響を与えることなく、破壊的な変更を許可します /api/v1/.

まとめ

追加的な変更を通じてAPIを進化させます。新しいフィールドの追加、新しいエンドポイントの追加、オプションパラメーターの追加などです。破壊的変更が避けられない場合は、APIバージョニングを使用して古いバージョンと新しいバージョンを同時に実行します。古いフィールドは、明確なタイムラインと移行ガイドを提示した上で非推奨とし、その後削除します。

よくある質問

ご質問がありますか?

どのような変更が破壊的変更と見なされますか?

レスポンスからのフィールドの削除、フィールド名の変更、フィールド型(文字列から数値など)の変更、オプションパラメータの必須化、既存の条件に対するHTTPステータスコードの変更、認証要件の変更、エラーレスポンス形式の変更。新しい必須リクエストパラメータの追加やエンドポイントの完全な削除も、破壊的変更となります。

クライアントを壊さずに新しい必須フィールドをどのように追加しますか?

新しいフィールドは、最初は適切なデフォルト値を持つオプションとして設定します。変更を文書化し、クライアントが採用する時間を与えます。十分な期間(公開APIの場合は6〜12か月)が経過した後、新しいAPIバージョンでそのフィールドを必須にします。バージョン管理なしで既存のオプションフィールドを必須にしないでください。

APIのバージョン管理と非推奨化の違いは何ですか?

バージョニングにより、古いエンドポイントと並行して新しいエンドポイント(/v2/users)が作成され、両方が共存できるようになります。非推奨化は、古いエンドポイントまたはフィールドを廃止予定としてマークしますが、機能は維持し、最終的な削除のタイムラインを設定します。大規模な変更にはバージョニングを、マイナーな機能の段階的な廃止には非推奨化を使用します。

非推奨のAPIバージョンはどのくらいの期間維持すべきですか?

公開APIの場合、非推奨バージョンを最低12~18か月間維持してください。内部APIの場合、クライアントチームと連携して移行スケジュールを調整してください。非推奨のエンドポイントを削除する前に、必ず事前通知(最低3~6か月前)を行ってください。シャットダウン前にクライアントが移行を完了していることを確認するため、使用状況のメトリクスを監視してください。

レスポンスフィールドの順序を変更できますか?

はい、JSONオブジェクトのフィールド順序はAPI契約の一部ではありません。適切に記述されたクライアントは、位置ではなくフィールド名でJSONを解析します。ただし、一部の不適切に記述されたクライアントはフィールド順序に依存する可能性があるため、十分にテストしてください。配列の場合、通常は順序が重要であり、文書化されていない限り変更すべきではありません。

URLパスを変更せずにAPIをどのようにバージョン管理しますか?

HTTPヘッダーを使用します:Accept: application/vnd.myapi.v2+json、またはAPI-Version: 2のようなカスタムヘッダーを使用します。クエリパラメータも機能します:/api/users?version=2。ヘッダーを介したコンテンツネゴシエーションはよりクリーンですが、ブラウザでのテストは困難です。いずれかの戦略を選択し、一貫して使用してください。

今すぐ、安全な環境へ。

コード、クラウド、ランタイムを1つの中央システムでセキュアに。
脆弱性を迅速に発見し、自動的に修正。

クレジットカードは不要です | スキャン結果は32秒で表示されます。