APIバージョン管理のベストプラクティスは?[閉まっている]


877

WebサービスREST APIバージョン管理の既知のハウツーまたはベストプラクティスはありますか?

AWSがエンドポイントのURLによってバージョン管理を行うことに気づきました。これが唯一の方法ですか、それとも同じ目標を達成する他の方法はありますか?複数の方法がある場合、それぞれの方法のメリットは何ですか?

回答:


682

これは良い質問です。URI設計のトピックは、同時にREST APIの最も顕著な部分であり、そのため、そのAPIのユーザーに対する長期的なコミットメントになる可能性があります

アプリケーションの進化と、それほどではありませんが、そのAPIは現実の事実であり、プログラミング言語のように複雑に見える製品の進化にさえ似ているため、URI設計の自然な制約は少なく、保存する必要があります時間の経過とともに。アプリケーションとAPIの寿命が長いほど、アプリケーションとAPIのユーザーへの取り組みが大きくなります。

一方、APIを介して消費されるすべてのリソースとその側面を予測することは困難です。幸い、Apocalypseまで使用されるAPI全体を設計する必要はありません。すべてのリソースエンドポイントとすべてのリソースおよびリソースインスタンスのアドレス指定スキームを正しく定義することで十分です。

時間の経過とともに、特定の各リソースに新しいリソースと新しい属性を追加する必要がある場合がありますが、特定のリソースにアクセスするためにAPIユーザーが従う方法は、リソースアドレス指定スキームがパブリックになり、最終的には変更されません。

このメソッドは、HTTP動詞のセマンティクス(たとえば、PUTは常に更新/置換する必要があります)および以前のAPIバージョンでサポートされているHTTPステータスコードに適用されます(人の介入なしで機能していたAPIクライアントが機能し続けることができるように機能し続ける必要があります)そのような)。

さらに、APIバージョンをURIに埋め込むと、アプリケーションの状態のエンジンとしてハイパーメディアの概念(Roy T. Fieldings PhDの論文に記載)が時間とともに変化するリソースアドレス/ URIを持つことにより混乱するため、そのAPIを結論付けます。バージョンは、長い時間のためのリソースのURIに保管してはならないことを意味APIのユーザーが依存することができ、リソースのURIはパーマリンクでなければなりません

確かに、それがベースURIに埋め込むAPIバージョンに可能であるが、唯一のAPIクライアントのデバッグなどの合理的かつ制限された用途のための新しいAPIのバージョンで動作します。このようなバージョン管理されたAPIは時間制限があり、限定されたAPIユーザーのグループ(クローズドベータ期間中など)のみが使用できるようにする必要があります。それ以外の場合は、すべきでない場所に自分をコミットします。

有効期限のあるAPIバージョンのメンテナンスに関するいくつかの考え。Webサービス(Java、.NET、PHP、Perl、Railsなど)の実装に一般的に使用されるすべてのプログラミングプラットフォーム/言語により、WebサービスのエンドポイントをベースURIに簡単にバインドできます。このようにして、さまざまなAPIバージョン間でファイル/クラス/メソッドのコレクションを簡単に収集して保持できます

APIユーザーのPOVから、特定のAPIバージョンの操作が簡単で、特定のAPIバージョンにバインドするのが簡単です。ただし、これは限られた時間、つまり開発中のみです。

APIメンテナーのPOVから、主にファイルを(ソースコード)バージョン管理の最小単位として機能するソース管理システムを使用することで、異なるAPIバージョンを並行して維持することがより簡単になります。

ただし、APIバージョンがURIで明確に表示される場合は注意が必要です。API履歴がURI設計で表示/非表示に なり、RESTのガイドラインに反する時間の経過とともに変化する傾向があるためこのアプローチに反対することもできます。同意する!

この合理的な異論を回避する方法は、バージョンのないAPIベースURIで最新のAPIバージョンを実装することです。この場合、APIクライアント開発者は次のいずれかを選択できます。

  • 最新のものに対抗して開発します(アプリケーションの維持を約束し、不適切に設計されたAPIクライアントを壊す可能性のある最終的なAPI変更からアプリケーションを保護します)。

  • 特定のバージョンのAPI(これは明らかになります)にバインドしますが、期間は限定されます

たとえば、API v3.0が最新のAPIバージョンである場合、次の2つはエイリアスにする必要があります(つまり、すべてのAPIリクエストと同じように動作します)。

http:// shonzilla / api / customers / 1234 
http:// shonzilla / api /v3.0 / customers / 1234
http:// shonzilla / api / v3 / customers / 1234

さらに、古い API を引き続き参照しようとするAPIクライアントは、使用しているAPIバージョンが廃止されているかサポートされなくなっている場合、最新の以前のAPIバージョンを使用するよう通知される必要があります。したがって、次のような古いURIにアクセスします。

http:// shonzilla / api /v2.2 / customers / 1234
http:// shonzilla / api /v2.0 / customers / 1234
http:// shonzilla / api / v2 / customers / 1234
http:// shonzilla / api /v1.1 / customers / 1234
http:// shonzilla / api / v1 / customers / 1234

このままである適切なバージョンのリソースURIにリダイレクトするHTTPヘッダーと共に使用されるリダイレクトを示す30x HTTPステータスコードのいずれかを返す必要がありますLocation

http:// shonzilla / api / customers / 1234

APIバージョン管理シナリオに適した少なくとも2つのリダイレクトHTTPステータスコードがあります。

  • 301永続的に移動され、リクエストされたURIを持つリソースが別のURI(APIバージョン情報を含まないリソースインスタンスパーマリンクである必要があります)に永続的に移動されたことを示します。このステータスコードを使用して、廃止またはサポートされていないAPIバージョンを示し、バージョン付きリソースURIがリソースパーマリンクに置き換えられたことをAPIクライアントに通知できます。

  • 302要求されたリソースが一時的に別の場所にあるが、要求されたURIはまだサポートされている可能性があることを示す発見。このステータスコードは、バージョンのないURIが一時的に利用できず、リダイレクトアドレスを使用してリクエストを繰り返す必要がある場合(APiバージョンが埋め込まれたURIを指すなど)、クライアントにそれを使用し続けるように伝えたい場合(つまり、パーマリンク)。

  • 他のシナリオは、HTTP 1.1仕様のRedirection 3xxの章にあります。


142
URLでバージョン番号を使用することは、基礎となる実装が変更された場合に悪い習慣と見なされるべきではありません。「サービスへのインターフェースが下位互換性のない方法で変更されると、実際にはまったく新しいサービスが作成されます...クライアントの観点から見ると、サービスはインターフェースであり、一部の非機能的な品質にすぎません。サービスへのインターフェースが下位互換性のない方法で変更された場合、それはもはや元のサービスのインスタンスを表すのではなく、完全に新しいサービスです。」ibm.com/developerworks/webservices/library/ws-version
benvolioT 2010

7
クライアントや開発者が確認できるように、バージョン番号を含むヘッダーを追加することについて何か考えはありますか?
webclimber 2010年

11
Acceptヘッダーを使用して、クライアントが期待するバージョンを示すことも参照してください。blog.steveklabnik.com
Weston Ruter

52
最後の部分について:410 Goneリダイレクトが新しい場所に互換性がない場合に互換性があることを示す可能性があるため、廃止され、サポートされなくなったAPIはを返す必要があると言います。APIが廃止されただけでまだ存在する場合はWarning、応答のHTTPヘッダーがオプションである可能性があります。
Michael Stum

22
shonzilla / api / customers / 1234のようなすでに安定したURLを使用していて、新しいバージョンにアップグレードしたいクライアントにどのように対処しますか?どうすれば、V2(古いバージョン)をURLに強制的に追加できますか?
デジェル2013

273

URLにはバージョンを含めないでください。バージョンは、要求しているリソースの「アイデア」とは関係ありません。URLは、アイテムの返却方法ではなく、希望する概念へのパスであると考えてください。バージョンは、オブジェクトの概念ではなく、オブジェクトの表現を決定します。他のポスターが言ったように、あなたはリクエストヘッダーでフォーマット(バージョンを含む)を指定するべきです。

バージョンのあるURLの完全なHTTPリクエストを見ると、次のようになります。

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

ヘッダーには、要求している表現を含む行が含まれています( "Accept:application / xml")。それはバージョンが行くべきところです。同じものが別のフォーマットで必要な場合があり、クライアントが必要なものを要求できるはずであるという事実は誰もが気にしないようです。上記の例では、クライアントが求めているため、ANYない、本当にそれが欲しいものの真の表現-リソースのXML表現。理論的には、サーバーがXMLであり、それが間違っていることを認識するために解析する必要がある限り、リクエストとはまったく無関係の何かを返す可能性があります。

より良い方法は:

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

さらに、クライアントがXMLが冗長すぎると考え、今では代わりにJSONが必要だとしましょう。他の例では、同じ顧客の新しいURLが必要になるため、次のようになります。

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(または類似の何か)。実際、すべてのHTTPリクエストには、探しているフォーマットが含まれています。

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

この方法を使用すると、設計の自由度が大幅に向上し、RESTの元のアイデアを実際に遵守できます。クライアントを中断することなくバージョンを変更したり、APIが変更されたときにクライアントを段階的に変更したりできます。表現のサポートを停止することを選択した場合、HTTPステータスコードまたはカスタムコードでリクエストに応答できます。クライアントは、応答が正しい形式であることを確認し、XMLを検証することもできます。

他にも多くの利点があり、そのうちのいくつかをブログでここで説明しています。http//thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

URLにバージョンを配置する方法が悪いことを示す最後の例です。オブジェクト内にいくつかの情報が必要で、さまざまなオブジェクトにバージョンを付けたとします(顧客はv3.0、注文はv2.0、shiptoオブジェクトはv4.2)。クライアントで指定しなければならない厄介なURLは次のとおりです。

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

10
Acceptヘッダーで独立したデータコントラクトバージョンとサービスコントラクトバージョンを処理することは、URLが乱雑であるのと同じくらい乱雑に見えます。他のオプションはありますか?また、複数のエンドポイント(soap、rest)がある場合、これもAcceptsに示され、サーバーエンドのルーティングサービスが正しいエンドポイントへの方向を決定できるようにする必要がありますか、それともエンドポイントをURLにコーディングしても問題ありませんか?
ideafountain 2011

117
少なくともあなたの最後の理由までは、私はこれに同意することはできません。これは、URIのさまざまな部分にさまざまなバージョンがあることを示しているようです。しかし、それはAPIバージョンのポイントではありません。ポイントは、ENTIREリソースのバージョンを1つにすることです。バージョンを変更すると、それは別のAPIリソースになります。それは見て意味がない理由ですcompany.com/api/v3.0/customer/123/v2.0/orders/4321ではなくcompany.com/api/v3.0/customer/123/orders/4321をリソースの特定の部分をバージョン管理するのではなく、リソース全体をバージョン管理します。
fool4jesus 2013年

90
ヘッダーでバージョン番号を意味的に使用する方が良いようです。しかし、URLを使用する方がはるかに実用的です。エラーが発生しにくく、デバッグが容易で、開発者が簡単に確認でき、残りのテストクライアントで簡単に変更できます。
Daniel Cerecedo 2013年

7
BAD / GOODは問題を単純化すると思います。APIは「アプリケーションプログラミングインターフェース」の略で、バージョン管理インターフェースは非常に良い考えのようです。APIは、単にリソースを提供するだけのものではありません。分離する必要があるのは、インターフェイスについて話している人もいれば、リソースについて話している人もいます。[ネットワーク]タブでGoogle Maps APIをよく見ると、URLにAPIバージョン番号が含まれていることがわかります。例:認証中のmaps.google.com/maps/api/jsv2。jsv2はAPI番号です。
トム・グルーナー2013

6
@Gili:実際には、RFC6648で-x非推奨になっているため、使用しないでください。
ジョナサンW

98

URLにバージョンを含めることは実用的で便利であることがわかりました。使用しているものを一目で簡単に確認できます。受け入れられた回答が示唆するように、使いやすさのために/ foo /(最新バージョン)のエイリアスとして/ fooを使用し、URLを短く/よりクリーンにします。

下位互換性を永続的に維持することは、多くの場合、コストがかかり、非常に困難です。非推奨、ここで提案されているようなリダイレクト、ドキュメント、およびその他のメカニズムについて事前に通知することをお勧めします。


5
受け入れられた答えは、正しい、最も純粋なものかもしれません。ただし、APIの開発者および日々のユーザーにとって、これは確かに最も簡単に使用および設定できます。最も実用的なアプローチ。他のGoogleやAmazonが示しているように、このアプローチも使用しています。
Muhammad Rehan Saeed

46

リソース表現のバージョン管理はRESTのアプローチに従っていることに同意しますが、カスタムMIMEタイプ(またはバージョンパラメータを追加するMIMEタイプ)の大きな問題の1つは、HTMLのAcceptおよびContent-Typeヘッダーへの書き込みが不十分であることです。 JavaScript。

たとえば、リソースを作成するために、IMOがHTML5フォームで次のヘッダーを使用してPOSTすることはできません。

Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json 

これは、HTML5 enctype属性が列挙型であるため、通常以外のものapplication/x-www-formurlencodedmultipart/form-dataありtext/plain、無効であるためです。

...また、HTML4のすべてのブラウザでサポートされていることも確かです(これにはより緩やかなencytpe属性がありますが、MIMEタイプが転送されたかどうかに関するブラウザ実装の問題になります)

このため、バージョン管理の最も適切な方法はURI経由であると感じていますが、これは「正しい」方法ではないことを受け入れます。


14
ヘッダーでバージョン管理が定義されたルートを想定すると、ネイティブフォームの送信を使用するHTMLフォームは、準拠したい特定のバージョンを渡さないため、常に最新バージョンのAPIを使用すると言えます。ただし、XHRリクエストでは実際に受け入れを変更してコンテンツタイプヘッダーを読み取ることができます。ですから、基本的なフォームが本当に唯一の問題です。
カイル・ヘイズ

URIが最も適切であることに同意するかどうかはわかりませんが、Content-Typeがフォームで機能しないという事実は、非常に重要です。
wprl 2013

2
@Kyle、ブログのどこかで、リクエストヘッダーにバージョンを指定しない場合は、互換性を保つために最新のAPIバージョンではなく、最初のAPIバージョンを返すのが最適だと述べました。
アンディ2014年

私が考えている今、それは実際に私には多くの意味があります。
カイル・ヘイズ

@KyleHayesは、iframe、video / embed、およびその他の「src / href」タイプのタグを忘れません。
2015年

21

URIにバージョンを入力します。APIの1つのバージョンが常に別のバージョンのタイプをサポートするわけではないため、リソースが1つのバージョンから別のバージョンに移行されるだけであるという主張は、明らかに間違っています。これは、フォーマットをXMLからJSONに切り替えることと同じではありません。タイプが存在しないか、意味的に変更されている可能性があります。

バージョンはリソースアドレスの一部です。あるAPIから別のAPIにルーティングしています。ヘッダーでアドレス指定を非表示にすることはRESTfulではありません。


13

REST APIでバージョニングを実行できる場所がいくつかあります。

  1. 前述のとおり、URI内。これは扱いやすく、リダイレクトなどが適切に使用されている場合、審美的にも快適です。

  2. Accepts:ヘッダーで、バージョンはファイルタイプにあります。「mp3」と「mp4」のように。これも機能しますが、IMOは少しうまく機能しません...

  3. リソース自体。多くのファイル形式には、通常はヘッダーにバージョン番号が埋め込まれています。これにより、サポートされていない(新しい)バージョンが指定されている場合、古いソフトウェアはパントすることができますが、新しいソフトウェアはファイルタイプのすべての既存のバージョンを理解することで「機能する」だけです。REST APIのコンテキストでは、URIを変更する必要はなく、渡されたデータの特定のバージョンへの応答だけが必要です。

3つのアプローチすべてを使用する理由がわかります。

  1. 新しいAPIを「クリーンスイープ」したい場合、またはそのようなアプローチが必要なメジャーバージョンの変更の場合
  2. クライアントがPUT / POSTを実行する前に、それが機能するかどうかを知りたい場合。
  3. クライアントがPUT / POSTを実行して、機能するかどうかを確認する必要がある場合は問題ありません。

8

REST APIのバージョン管理は、他のAPIのバージョン管理に似ています。小さな変更を行うことができます。大きな変更には、まったく新しいAPIが必要になる場合があります。あなたにとって最も簡単なのは、毎回ゼロから始めることです。これは、URLにバージョンを入れることが最も理にかなっている場合です。クライアントの生活をより簡単にしたい場合は、下位互換性を維持しようとします。これは、廃止(永続的なリダイレクト)、複数のバージョンのリソースなどで実行できます。これはより手間がかかり、より多くの努力が必要です。しかし、それはRESTが「クールなURIは変更しない」で推奨していることでもあります。

結局のところ、それは他のAPIデザインと同じです。努力をクライアントの利便性と比較検討します。APIにセマンティックバージョニングを採用することを検討してください。これにより、新しいバージョンの下位互換性がクライアントに明確になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.