岩本隆史の日記帳(アーカイブ)

はてなダイアリーのサービス終了をうけて移行したものです。更新はしません。

続・コマンド的な処理をどうやってRESTfulに実装するか

コマンド的な処理をどうやってRESTfulに実装するか」に書いた内容を敷衍します。

SunのクラウドサービスAPI

先日、Sun MicrosystemsがSun Cloudというクラウドサービスを提供すると発表しました。

この記事には、クラウド操作用APIがRESTベースで提供される予定であることも書かれています。

Sunは開発者向けにクラウドAPI「Sun Open Cloud API」を提供する。RESTベースのAPIで、CreativeCommonsライセンスの下でリリースするため、開発者はSun Cloudと相互運用性のあるクラウドを構築できるという。

そのAPI仕様のドラフトが「The APIs for the Sun Cloud: Wiki: Home — Project Kenai」です。フォーラムではAPIに関する議論が交わされています。

コマンド的な処理をどうやってRESTfulに実装するか

その議論の中で、SunのTim Bray氏がバーチャルマシン(VM)をリブートするAPIの実装について触れています。「リブート処理は冪等ではないからPUTは使えない」というのです。そしてその意見を自身のブログでも公開しました(「ongoing · RESTful Casuistry」)。

私にはリブート処理は冪等にみえるのですが(何度リクエストしても結果が変わらないため)、本質的な問題は、冪等でないコマンド的な処理をどうやってRESTfulに実装するか、ということでしょう。

POSTで構わない

そんなTim Bray氏の疑問に、RESTの提唱者であるRoy T. Fielding氏が応答しました(「It is okay to use POST » Untangled」)。タイトルの通り、POSTで構わないという意見です。

RESTful Webサービス』で展開されたリソース指向アーキテクチャROA)では、POSTは主に従属リソースの生成に使うべきで、それ以外の使い方(オーバーロードPOST)は統一性が低いと位置づけられています。リソースの状態を更新するにはPUTを使う、といったCRUD的な考え方です。しかしRoy T. Fielding氏は、そのような考え方を否定します。

少し長いですが、一部を引用します。

POST only becomes an issue when it is used in a situation for which some other method is ideally suited: e.g., retrieval of information that should be a representation of some resource (GET), complete replacement of a representation (PUT), or any of the other standardized methods that tell intermediaries something more valuable than “this may change something.” The other methods are more valuable to intermediaries because they say something about how failures can be automatically handled and how intermediate caches can optimize their behavior. POST does not have those characteristics, but that doesn’t mean we can live without it. POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”

GETやPUTやDELETEのように明確なメソッドに当てはまらない処理ならば、POSTが使える、という意見です。

実装例

氏は、自分であればこのように実装するとも述べています。

Personally, I would just use POST for that button. The API can compensate for the use of POST by responding with the statement that the client should refresh its representation of the larger resource state. In other words, I would return a 303 response that redirected back to the VM status, so that the client would know that the state has changed.

私なりに具体化すると、下記のようになります。

リクエス
POST /vms/33333
control=reboot
レスポンス
303 See Other
# Location: /vms/33333  ←すみません、不適切でした(id:yoheiさん、ご指摘ありがとうございます)
Location: http://example.com/vms/33333

リブートの進捗状況リソースを作るかどうかは、そのリソースがどれだけ重要かによるでしょう。特に重要でないなら、VMリソースにリダイレクトして、そこで確認してもらえばよいわけです。

こうした実装は、ROAの観点からはオーバーロードPOST以外の何物でもありません。しかし、完全にRESTfulであり、色々と応用がききます。たとえばブックマーク一覧から複数のブックマークを削除する場合ならば:

POST /bookmarks
command=delete&id=3&id=5&id=8
303 See Other
# Location: /bookmarks  ←これも不適切でした
Location: http://example.com/bookmarks

などとできます。

もちろん、ROA式の、個別にDELETEする実装と共存させてもよいでしょう。

DELETE /bookmarks/3
DELETE /bookmarks/5
DELETE /bookmarks/8