RESTful API の後方互換性
経緯
ナビゲーショナルに次の要求を決定できるということは。REST 的な重要な特徴であるのは疑う余地はありません。この特徴は念頭においた上での今回の問題提起でした。
#rws 後方互換性を破壊するようは変更が出て来ることを考えると。API の非互換バージョンごとに URI セットを振り分けられるようになっているのが望ましい。では、URI に互換バージョンを表す識別子を含めるか。それはそれで気持ちよくない。
http://wassr.jp/user/siena/statuses/A1STwc4qWx
これに対して、id:IwamotoTakashi (id:iwamot) さんから次のような記事をいただきました。
「APIの後方互換性」問題は、そもそも気にならないということになります。互換性が気になるのは、クライアントとサーバが密結合しているサインだといえるでしょう。
http://d.hatena.ne.jp/IwamotoTakashi/20090501/p1
ある特定の時点での API のスナップショットについては。id:IwamotoTakashi さんの記事の最終段落より前に書かれている通りです (これに関連した、あるいは、派生した論点はあるかもしれませんが、措いておきます)。
しかし。ここでの急所は、「後方互換性を破壊するような変更」であり。着目点は、変更前後の API のスナップショット間の関係です。その前段までの説明と、この問題には、直接の関係はありません。
というわけで。考察の過程の説明に、もう少し言葉を費やしてみることにしましょう。どなたかが、論理の穴をついてくれることを期待して。
前提の確認
まず、クライアントから除くことのできない処理要件は。「応答として得られたリソース表現である文書を適切に処理する」といったことでしょう。ここで考える「処理」は、次が主要なものだと考えます。
- 1. 文章中から部分データを抽出し、必要なら別の構造を持つデータに再構成する
- 2. 適切なワークフロー (もしくはデータフロー) となるようなリンクを選択し、必要ならばパラメータを設定して、要求を送る
- ※ リンクはフォームとして与えられるものも含めます
ある情報を得るために利用される URI は、次のように取得されるとしましょう。
- URI 取得方法 A.
- あるクライアントが、API 変更前に既にリンク先の URI を取得していて、API 変更後にそれを用いて要求を発行しようとすることは十分にありえます。リソースがアドレス可能なのですから、これは自然なことです。
API 変更の影響と後方互換性の維持
さて、API が変更された時。
一般に、クライアントが同時に追従することはできません。たとえ事前に変更が周知されていたとしても、開発者の都合ですぐにはメンテナンスされないかもしれません。
ですから。クライアントの動作を破壊しないために。前述の A. 既知の URI、もしくは B. メディアタイプと関係名から決定された URI、に対する要求は。いずれも、API の変更前に対して、変更後も後方互換性が保たれている、即ち。既知の要求を全て受理可能であり、かつ、既存の API で期待される結果と競合しない副作用のみを発生させ、かつ、上位互換な結果文書を返す必要があります。そうでないと、クライアントは困ってしまいかねません。例えば、適切なワークフローとなるようなリンクを選んだはずなのに、予期しない副作用によって処理が破綻したり。応答文書が予期しない構造になっていて、想定していた処理ができなくなったり。
では、後方互換性を失う変更をする場合にどうすれば良いでしょうか。まず、A. に対して後方互換性を保つためには、従来の URI を持つリソース X はそのままにして。異なる URI を持つリソース X' を新たに定義し、他から参照されるようにリンク関係を変更するのが簡明でしょう。
ただし、そのリンク元となっているあるリソース Y と新しいリソース X' はリンクされ、一組のものとして扱われることになります。このため、全体としては、まだ B. に対して後方互換性を保てていません。なぜなら、API 変更前のリソース Y に到達した古いクライアントは、リンクを辿って X' に到達してしまうからです。
というわけで、後方互換性を維持するためには。Y に対して X' を参照するような変更をするのではなく。X' へのリンクを持つ Y' というリソースとして新たに定義することになります。こうやって、更に影響範囲を遡って括り出していくと。結局、API 変更前/変更後のリソース群が独立して存在することになるわけで。即ち、それぞれが異なるバージョンの API を表現していることになります。