1. 問題

REST APIの進化は難しい問題であり、多くのオプションが利用可能です。 この記事では、これらのオプションのいくつかについて説明します。

2. 契約には何が含まれていますか?

何よりもまず、1つの簡単な質問に答える必要があります: APIとクライアント間の契約は何ですか?

2.1. 契約のURI部分?

最初にRESTAPIのURI構造について考えてみましょう–それは契約の一部ですか? クライアントはブックマークし、ハードコードし、一般的にAPIのURIに依存する必要がありますか?

この場合、クライアントとRESTサービスの相互作用は、サービス自体ではなく、RoyFieldingが呼び出す帯域外情報によって駆動されます。

REST APIは、最初のURI(ブックマーク)と対象読者に適した標準化されたメディアタイプのセット以外の事前知識なしで入力する必要があります…ここでの失敗は、帯域外情報がハイパーテキストではなくインタラクションを促進していることを意味します。

したがって、明らかにURIは契約の一部ではありません。 クライアントは、APIへのエントリポイントである単一のURIのみを知っている必要があります。 他のすべてのURIは、APIの使用中に検出する必要があります。

2.2. メディアタイプは契約の一部ですか?

リソースの表現に使用されるメディアタイプ情報についてはどうですか?これらはクライアントとサービスの間の契約の一部ですか?

APIを正常に使用するには、クライアントはこれらのメディアタイプに関する事前の知識を持っている必要があります。 実際、これらのメディアタイプの定義は、契約全体を表しています。

したがって、これはRESTサービスが最も焦点を当てるべき場所です。

REST APIは、リソースの表現やアプリケーションの状態の駆動に使用されるメディアタイプの定義、または既存の標準メディアタイプの拡張リレーション名やハイパーテキスト対応のマークアップの定義に、ほとんどすべての記述的な作業を費やす必要があります。

したがって、メディアタイプ定義はコントラクトの一部であり、APIを使用するクライアントの事前知識である必要があります。 これが標準化の出番です。

これで、コントラクトが何であるかがわかりました。次に、バージョン管理の問題に実際に取り組む方法に移りましょう。

3. 高レベルのオプション

次に、RESTAPIをバージョン管理するための高レベルのアプローチについて説明します。

  • URIバージョン管理–バージョンインジケーターを使用してURIスペースをバージョン管理します
  • メディアタイプのバージョン管理–リソースの表現のバージョン管理

URIスペースにバージョンを導入する場合、リソースの表現は不変と見なされます。したがって、APIに変更を導入する必要がある場合は、新しいURIスペースを作成する必要があります。

たとえば、APIが次のリソース(ユーザーと特権)を公開するとします。

http://host/v1/users
http://host/v1/privileges

ここで、 users APIの重大な変更には、2番目のバージョンの導入が必要であると考えてみましょう。

http://host/v2/users
http://host/v2/privileges

メディアタイプをバージョン管理して言語を拡張する場合、このヘッダーに基づいてコンテンツネゴシエーションを実行します。 REST APIは、汎用メディアタイプの代わりにカスタムベンダーMIMEメディアタイプを使用します application /jsonなど。 URIの代わりにこれらのメディアタイプをバージョン管理します。

例えば:

===>
GET /users/3 HTTP/1.1
Accept: application/vnd.myname.v1+json
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.myname.v1+json
{
    "user": {
        "name": "John Smith"
    }
}

この主題に関する詳細と例については、この「RESTAPIのカスタムメディアタイプ」の記事を確認できます。

ここで理解することが重要なのは、クライアントは、メディアタイプで定義されているものを超えて、応答の構造について何も想定していないということです。

これが、一般的なメディアタイプが理想的ではない理由です。 これらのは十分なセマンティック情報を提供せず、クライアントにリソースの実際の表現を処理するために追加のヒントを要求するように強制します。

これの例外は、XMLスキーマなど、コンテンツのセマンティクスを一意に識別する他の方法を使用することです。

4. 長所と短所

クライアントとサービス間のコントラクトの一部であるものの明確な概念と、APIをバージョン管理するためのオプションの概要がわかったので、各アプローチの長所と短所について説明しましょう。

まず、 URIにバージョン識別子を導入すると、URIフットプリントが非常に大きくなります。これは、公開されたAPIのいずれかに重大な変更を加えると、API全体の表現のまったく新しいツリーが導入されるためです。 。 時間が経つにつれて、これは維持する負担になるだけでなく、クライアントにとっても問題になります。これにより、選択できるオプションが増えました。

URIのバージョン識別子も非常に柔軟性がありません。 単一のリソースのAPI、またはAPI全体の小さなサブセットを単純に進化させる方法はありません。

前に述べたように、これはオールオアナッシングアプローチです。 APIの一部が新しいバージョンに移行する場合、API全体も一緒に移行する必要があります。 これにより、クライアントをv1からv2にアップグレードすることも重要な作業になります。これにより、アップグレードが遅くなり、古いバージョンのサンセット期間が大幅に長くなります。

バージョン管理に関しては、HTTPキャッシングも大きな懸念事項です。

中間のプロキシキャッシュの観点から、各アプローチには長所と短所があります。 URIがバージョン管理されている場合、キャッシュは各リソースの複数のコピーを保持する必要があります(APIのバージョンごとに1つ)。 これにより、キャッシュに負荷がかかり、異なるクライアントが異なるバージョンを使用するため、キャッシュヒット率が低下します。

また、一部のキャッシュ無効化メカニズムは機能しなくなります。 メディアタイプがバージョン管理されているものである場合、クライアントとサービスの両方が Vary HTTPヘッダーをサポートして、キャッシュされている複数のバージョンがあることを示す必要があります。

ただし、クライアントキャッシングの観点から、メディアタイプをバージョン管理するソリューションは、URIにバージョン識別子が含まれるソリューションよりもわずかに多くの作業を伴います。 これは、キーがメディアタイプよりもURLである場合に、何かをキャッシュする方が簡単だからです。

いくつかの目標を定義してこのセクションを終了しましょう( API Evolution から直接):

  • 互換性のある変更を名前から除外する
  • 新しいメジャーバージョンを避ける
  • 下位互換性のある変更を行います
  • 上位互換性について考える

5. APIへの可能な変更

次に、RESTAPIへの変更の種類について考えてみましょう。これらはここで紹介されています。

  • 表現形式の変更
  • リソースの変更

5.1. リソースの表現への追加

メディアタイプのフォーマットドキュメントは、上位互換性を念頭に置いて設計する必要があります。 具体的には、クライアントは理解できない情報(どのJSONがXMLよりも優れているか)を無視する必要があります。

現在、リソースの表現に情報を追加しても、これらが正しく実装されていれば、既存のクライアントが破損することはありません。

前の例を続けるために、userの表現にamountを追加しても、重大な変更にはなりません。

{
    "user": {
        "name": "John Smith", 
        "amount": "300"
    }
}

5.2. 既存の表現の削除または変更

既存の表現の設計における情報の削除、名前の変更、または一般的な再構築は、クライアントにとって重大な変更です。これは、クライアントがすでに古い形式を理解し、依存しているためです。

これがコンテンツネゴシエーションの出番です。 このような変更については、新しいベンダーのMIMEメディアタイプを追加できます。

前の例を続けましょう。 ユーザー名前に分割するとします。

===>
GET /users/3 HTTP/1.1
Accept: application/vnd.myname.v2+json
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.myname.v2+json
{
    "user": {
        "firstname": "John", 
        "lastname": "Smith", 
        "amount": "300"
    }
}

そのため、これはクライアントにとって互換性のない変更を表します。これは、新しい表現を要求し、新しいセマンティクスを理解する必要があります。 ただし、URIスペースは安定したままであり、影響を受けません。

5.3. 主な意味変化

これらは、リソースの意味、リソース間の関係、またはバックエンドでのマップの変更です。この種の変更には、新しいメディアタイプが必要な場合や、新しい兄弟リソースの公開が必要な場合があります。古いものの隣にあり、それを指すためにリンクを利用しています。

これはURIでバージョン識別子を繰り返し使用しているように聞こえますが、重要な違いは、新しいリソースがAPI の他のリソースとは独立して公開され、ルートでAPI全体をフォークしないことです。

REST APIは、HATEOAS制約に準拠する必要があります。 これによると、ほとんどのURIは、ハードコードされているのではなく、クライアントによって検出される必要があります。 このようなURIの変更は、互換性のない変更と見なされるべきではありません。 新しいURIは古いURIを置き換えることができ、クライアントはURIを再検出して、引き続き機能することができます。

ただし、URIでバージョン識別子を使用することはこれらすべての理由で問題がありますが、それは決して非RESTfulではないことに注意してください。

6. 結論

この記事では、RESTサービスの進化の非常に多様で困難な問題の概要を説明しました。 2つの一般的なソリューション、それぞれの長所と短所、およびRESTのコンテキストでこれらのアプローチについて推論する方法について説明しました。

この記事は、2番目のソリューションであるメディアタイプのバージョン管理を行い、RESTfulAPIへの変更の可能性を検討することで締めくくります。

このチュートリアルの完全な実装は、GitHubプロジェクトにあります。

7. 参考文献

通常、これらの読書リソースは記事全体でリンクされていますが、これらの場合、単に良いものが多すぎます。