BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース RESTとバージョニング

RESTとバージョニング

原文(投稿日:2010/06/13)へのリンク

最近Ganesh Prasad氏はRESTアーキテクチャにおけるサービスのバージョニングという非常に悩ましいテーマについて検討している。例えば

"/customers/1234"で表わされるリソースがあるとします。この顧客情報の状態を更新するためにPUTが必要です。しかし、PUTに対応するビジネスロジックの更新を、RESTはどうやって取り扱えるのでしょうか?

サービス(ビジネスロジック)を指定するために使用されるオペレーションを変更する(例:PUTv2を指定する)方法は存在しない。選択肢の1つはPUT対象のURLを変更し、同時に元のURLもメンテナンスすることだ。Ganesh氏は以下のような例を示している。

/customers/1234というURLは残し、PUTはそれとは別のURL /customers/v2/1234 に対して行います。

これは数年前のPeter Williams氏の議論それ以前に話題に上っていた、アンチパターンと同じものである。2008年の段階で、Peter氏はこのように述べている。

あるバージョンのAPIでの顧客情報が、別のバージョンのAPIでは異なるリソースとなってしまうので、私は本当にこのアプローチが嫌いです。このアプローチはサービスのクライアントに対して、一度に複数のバージョンをサポートするか、もしくはRESTの核となる制約の1つを破るか、というたちの悪い選択を強要することにもなります。例えば、顧客情報を保存するAPI v1(URIがバージョン識別子を含んでいる)を利用したクライアントがあり、これからクライアントを新しいバージョンのAPIに対応させるとします。この場合、クライアントで同時に両方のバージョンをサポートするか、もしくはURIを全て新API用に変更するという方法があります。全てのURIを変更するとRESTのHATEOAS制約を破ることになりますし、複数のバージョンのAPIをサポートすることはメンテナンス性の問題があります。

Peter氏はカスタムメディアタイプとコンテントネゴシエーションの組み合わせによるバージョニングを提案している(これらは最終的に後方互換ではない変更を発生させる)。

このアプローチではメディアタイプを作成する必要がありますが、簡単に我々が必要としていることを行えます。コンテントネゴシエーションも、適切に使用すればREST/HTTP Webサービスインターフェースのバージョニングに関する問題を解決することができます。

Ganesh氏の話に戻るが、彼もURLを修正するアプローチについては賛成していない。

何よりもまず、ビジネスロジックのバージョンを表わすことができるのが、HTTP Verbとリソースの2か所だけと考えるのは間違いです。送信されたデータは[...]第3の選択肢です。しかし、この例は私にバージョニングについての基本的な疑問を抱かせます。

Ganesh氏は次に、RESTやSOAのバージョニングとは何なのか?それはなぜ必要なのか?という問題について検討している。

私は、サービスのバージョニングとは、呼び出し可能なビジネスロジックを同時に維持することができるメカニズムであると考えています。

Ganesh氏はそもそもなぜ呼び出し元から見える必要があるのかと問うている。例えば、もしサービスが呼び出し元の種類を区別できれば、呼び出し元には透過的に、内部で異なるビジネスロジックを適用可能だろうか。更にGanesh氏は、なぜ同時に複数バージョンのビジネスロジックを維持する必要があるのか、と問いかけている。

興味深い回答は、ビジネスロジックは呼び出し元から「見える」ため、新しいバージョンのビジネスロジックは古いバージョンと区別できる必要があるというものです。これはよくレガシーな呼び出し元、例えば何らかの方法で前のバージョンのビジネスロジックに依存している呼び出し元のサポートのために必要になります。

レガシーなクライアントのサポートが必要なのは、サービスをアップグレードした時に、既存のコントラクトとSLAが壊れないことを保証するためである。これは、バージョニング問題の答えは明示的なバージョンを使うことではなく、具体的な詳細の中で見つかるのではないかという疑問にGanesh氏を導く。具体的な詳細というのは、言いかえるとサービスのコントラクトがより具体的で、変更が起こった時にはとてももろいということだ(SOAの裏にある、古くからの疎結合vs密結合という一連の考えと同じである)。

Ganesh氏は、呼び出し元がすでに存在しているサービスのビジネスロジックを変更するという具体例を用いて、このアプローチがどのようにバージョニング問題を解決するのに使われるのかを議論している。

最初の問題は、全ての呼び出し元に新しいビジネスロジックを適用できるのか、それとも"古い"呼び出し元には前のビジネスロジックを適用する必要があるのかということです。もし全ての呼び出し元を新しいビジネスロジックに"アップグレード"できるなら、インターフェースは元のまま残るので、もちろん何の問題もありません。クライアントアプリケーションは同一のURIにデータをポストし、新しく作成されたリソースに対して以前と同じようにリダイレクトされます。適用されたビジネスロジックが全く新しいものでも、呼び出し元にとっては、インターフェースに変更がないのです。

だがもちろん、これは不可能である。なぜなら、異なる複数のビジネスロジックのメンテナンスが要求されるからだ。Ganesh氏はなぜこのようなことが起こるのかについて、次のように列挙している。

  • クライアントアプリが送信するデータが変更されると、別の新しいコントラクトで通信しなければなりません。
  • ビジネス上の理由によって呼び出し元の種類を分ける場合。この場合、送信するデータによって分かれるかどうかは明確ではありません。
  • 呼び出し元が何らかの方法で昔のバージョンの振る舞いを知っており、それに依存している場合。この場合、前の呼び出し元を壊さないために、新しいバージョンが必要となります。

これによれば、3つ目はわざと呼び出し元とバックエンドの実装の間に依存関係を持たせ、疎結合を崩すことである。

対照的に、最初と2番目の理由はそれ自身が解決法となります。もし、クライアントによって送信されるデータの種類が変われば、新しいクライアントと古いクライアントを見分け、異なるビジネスロジックを適用することができます。つまり、POSTするデータが変わったことを呼び出し元に知らせればよいだけです。古い呼び出し元にはそれを伝える必要はありません。また、どうにかして(送信されたデータでなくても)既存のクライアントであることがわかれば、透過的に異なるビジネスロジックを適用することが可能です。

Ganesh氏はこのように主張して締めくくっている。

サービスのバージョンはインターフェースの詳細ではありません。それらは頻繁にインターフェースに現れる実装詳細です。

サービスのバージョニングはRESTだけでなく、多くの分野で頻繁に出てくる問題である。しかしGanesh氏は、RESTはこの問題に対してよりよく、より自然な解決策を提供すると信じている。

この記事に星をつける

おすすめ度
スタイル

BT