Aikido

パブリックAPIの契約を破棄しない方法:後方互換性の維持

メンテナンス性

ルール

避ける 破る パブリック API 契約書
変更点  パブリック API エンドポイント それは  既存の
既存の クライアント リクエスト  壊す を変更する。
考える 考えてみてください。 その API コントラクト  a 約束 - 変更
それを 後に クライアント 顧客が 変更する それ 休憩 彼らの コードを壊してしまう。

対応言語 PHP、 Java C#, Python JavaScript、 タイプスクリプト

はじめに

パブリック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)を作成し、両方の共存を可能にします。非推奨(Deprecation)は、古いエンドポイントやフィールドの機能を維持したまま、廃止されたものとしてマークするものです。大きな変更にはバージョニングを使用し、マイナーな機能を段階的に廃止するには非推奨を使用します。

非推奨の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つの中央システムでセキュアに。
脆弱性を迅速に発見し、自動的に修正。

クレジットカードは不要。