REST APIのバージョン管理

REST APIのバージョン管理

1. 問題

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

参考文献:

Spring Boot TestRestTemplateの調査

Spring Bootで新しいTestRestTemplateを使用して簡単なAPIをテストする方法を学びます。

JerseyとSpringを使用したREST API

Jersey 2とSpringを使用した安らかなWebサービスの構築。

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

何よりもまず、1つの簡単な質問に答える必要があります:What is the Contract between the API and the Client?

2.1. 契約のURI部分?

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

この場合、クライアントとRESTサービスの相互作用は、サービス自体ではなく、Roy Fielding callsout-of-bandの情報によって駆動されます。

REST APIは、最初のURI(ブックマーク)と、対象とする視聴者に適した標準化されたメディアタイプのセット以外の事前知識なしで入力する必要があります。

明らかにURIs are not part of the contract! クライアントは、APIへのエントリポイントである単一のURIのみを知っている必要があります。 APIを使用しながら、他のすべてのURIを検出する必要があります。

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

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

In order to successfully consume the API, the Client must have prior knowledge of these Media Types。 実際、これらのメディアタイプの定義は契約全体を表しています。

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

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

したがって、Media Type definitions are part of the contractは、APIを使用するクライアントの事前知識である必要があります。 これが標準化の出番です。

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

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

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

  • URI Versioning –バージョンインジケーターを使用してURIスペースをバージョン管理する

  • Media Type Versioning –リソースの表現のバージョン

When we introduce the version in the URI space, the Representations of Resources are considered immutable.したがって、APIに変更を導入する必要がある場合は、新しいURIスペースを作成する必要があります。

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

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

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

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

When we version the Media Type and extend the language, we go through Content Negotiation based on this header. REST APIは、application/jsonなどの一般的なメディアタイプの代わりにカスタムvendor MIME media typesを使用します。 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"
    }
}

このテーマに関する詳細と例については、この‘Custom Media Types for Rest APIs' articleを確認できます。

ここで理解することが重要なのは、the client makes no assumptions about the structure of the responseがメディアタイプで定義されているものを超えているということです。

これが、汎用メディアタイプが理想的でない理由です。 これらのdo not provide enough semantic informationは、クライアントに使用を強制し、リソースの実際の表現を処理するために追加のヒントを必要とします。

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

4. 長所と短所

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

まず、introducing version identifiers in the URI leads to a very large URI footprint.これは、公開されたAPIのいずれかで重大な変更が行われると、API全体の表現のまったく新しいツリーが導入されるためです。 時間が経つにつれて、これは維持する負担になるだけでなく、クライアントにとっても問題になります。現在、クライアントには選択肢が増えています。

Version identifiers in the URI ARE also severely inflexible。 単一のリソースのAPI、またはAPI全体の小さなサブセットを単純に進化させる方法はありません。

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

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

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

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

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

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

  • 互換性のある名前を変更しない

  • 新しいメジャーバージョンを避ける

  • 下位互換性のある変更を行います

  • 前方互換性について考える

5. APIへの可能な変更

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

  • 表現形式の変更

  • リソースの変更

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

メディアタイプの形式のドキュメントは、前方互換性を考慮して設計する必要があります。 具体的には、クライアントは理解できない情報を無視する必要があります(JSONはXMLよりも優れています)。

さて、adding information in the Representation of a resource will not break existing clients if these are correctly implemented.

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

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

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

Removing, renaming or generally restructuring information in the design of existing representations is a breaking change for clients.これは、彼らがすでに古い形式を理解して依存しているためです。

これがコンテンツネゴシエーションの出番です。 このような変更の場合、we can add a new vendor MIME media type.

前の例を続けましょう。 usernamefirstnamelastnameに分割するとします。

===>
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. 主な意味変化

These are changes in the meaning of the Resources, the relations between them or what the map to in the backend.この種の変更には、新しいメディアタイプが必要な場合や、古いリソースの隣に新しい兄弟リソースを公開し、それを指すリンクを利用する必要がある場合があります。

これはURIでバージョン識別子を繰り返し使用しているように聞こえますが、重要な違いは、新しいリソースis published independently of any other Resources in the APIがあり、ルートでAPI全体をフォークしないことです。

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

ただし、URIでバージョン識別子を使用することはこれらすべての理由で問題がありますが、it is not un-RESTfulは何らかの形で問題があることに注意してください。

6. 結論

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

この記事は、RESTful APIへの可能な変更を検討しながら、2番目のソリューションであるversioning the media typesを主張することで締めくくっています。

このチュートリアルの完全な実装は、GitHub projectにあります。

7. 参考文献

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