REST 入門(その8) REST でないもの
» Permanent link | |
» REST 入門 目次
WWW は REST アーキテクチャスタイルのアーキテクチャを採用した実装のひとつですが、 REST アーキテクチャスタイルでないアーキテクチャの WWW アプリケーションもかなり存在します。 REST でないものを一言で言ってしまうと、 URI と HTTP を正しく使っていないもの、ということになります。 以下では URI と HTTP の誤った使い方について説明します。
URI をクライアントで組み立てる
URI をクライアント側でごちょごちょ組み立てなければならないのなら、それは REST ではありません。 たとえば、はてなブックマーク AtomAPI が、こんなインターフェースだったらどうでしょう?
ブックマークをキーワードで検索する。
POST /uso/bookmarkSearchService HTTP/1.1 Host: b.hatena.ne.jp Content-Type: application/xml <keyword>REST</keyword>
レスポンスはブックマーク ID のリストになる。
HTTP/1.1 200 OK Content-Type: application/xml <resultList> <result id="332"/> <result id="55"/> <result id="9842"/> <result id="102944"/> </resultList>
クライアントは /resultList/result/@id を見て、ブックマークの ID を知る。 そのブックマークを GET するには、ブックマーク取得サービスに ID をパラメータで渡す。
GET /uso/getBookmark?id=332 HTTP/1.1 Host: b.hatena.ne.jp
なんか、変ですよね。 REST であれば、ここは当然ハイパーリンクで実現すべきです。
GET の濫用、または URI へのアクションの挿入
この問題は前節の問題とビミョーに絡んでいます。 例を見てみましょう。 ブックマークを削除するときに以下のような操作をするとします。 オペレーションが削除であることは action パラメータで指定して、 削除するブックマークは id パラメータで指定します。
GET /uso/bookmarkService?action=delete&id=332 HTTP/1.1
この方式がまずい点は二つあります。 ひとつは前節で述べたとおり URI をクライアントが組み立てなければならない点。 もうひとつはオペレーションを action というパラメータで URI に組み込んでいる点です。
action パラメータを URI に埋め込むのが駄目なのには理由が二つあります。 第一に HTTP メソッドのセマンティクスを正しく利用していない点。 HTTP にはきちんと DELETE メソッドがあります。 しかし、上の例では DELETE を使わずに、GET を使っています。 これは明らかに誤用です。
この例が駄目な二つ目の理由は GET でリソース副作用(side effect)がある操作をしている点です。 GET の重要な性質としてリソースに副作用を与えないということがありました。 しかし、この URI を GET をすると、URI が指定するリソースが削除されてしまいます。 これはセキュリティ上重大な欠陥となる可能性が強い HTTP の誤用です。 少し前に話題だった CSRF の一番典型的なパターンは、この GET の濫用でしょう。
POST の濫用
すでにその5で POST の濫用については説明しましたので、ここでは簡単に振り返っておきます。 POST は四つの HTTP メソッドの中で一番柔軟なメソッドです。 しかし、HTTP メソッド本来の意味を考えて POST メソッドを利用するのが正しいのは言うまでもありません。 POST を使うときの経験則として、POST をリソースの新規作成にだけ使う、ことをいつも念頭におきましょう。
HTTP 状態コードの誤用
HTTP の状態コード(ステータスコード)は大切です。 200 とか 404 とか 500 とか 302 あたりが有名ですね。 これらの番号を誤用すると、RESTful になりません。
たとえば、エラーが起きたときのことを考えましょう。 クライアントのリクエストが悪いのに 500 を返す。 あるいは逆にサーバが悪いのに 40X を返す。 どちらも間違いです。
また、結果は明らかにエラーなのに、エラーメッセージを表示するために 200 を返すのも間違いです。 あるいは、200 を返しながら、拡張 HTTP ヘッダで詳細コードを返す。 どちらも RESTful でありません。
クッキーとセッション
REST アーキテクチャスタイルの重要な制約のひとつにステートレスがあります。 ここでいうステートレスとは、 クライアントとサーバの間の接続が状態を持っていないことを意味します。 もう少し簡単にいうと、 クライアントからサーバに送られるリクエストメッセージには、 サーバがそのメッセージを処理するのに必要な情報がすべて含まれている、ということです。 このようにアーキテクチャの制約としてステートレスを加えると、 サーバ実装の簡略化とスケーラビリティの確保につながります。
しかし、現実の Web 実装ではそうでないものも多々ありますね。 HTTP をステートフルにする代表格はクッキーを使ったセッション管理です。 REST アーキテクチャスタイルの視点からみると、 クッキーを使ったセッション管理は間違った HTTP の拡張、ということになります。
HTTP と URI を使うだけでは十分でない
今回の話題をまとめると、「HTTP と URI を使うだけでは十分でない」ということに尽きますね。 いかに HTTP と URI を使って XML をやり取りしていても、 間違った使い方であれば、それは REST アーキテクチャスタイルに従った実装ではありません。
次回は REST と SOAP の関係を、ほんの少しだけ説明しようと思います。
P.S. この weblog のタイトルを変更しました。
5 Comments:
「URI をクライアントで組み立てる」のが問題であるなら、/resultList/result/@idの代わりに、/resultList/result/@uriにURIが含まれるようになっていれば良いということでしょうか?
NAGASAWA さん。そうです。uri 属性に URI が入っているなら、クライアントはその URI に対して GET/PUT/POST/DELETE/OPTIONS などの HTTP メソッドを発行することができます。
一方で id から URI を組み立てる場合、このサービスでは URI をどう組み立てればいいのか、という情報を知らなければなりません。これはクライアントが知らなければならない条件が多くなるという意味で密結合となります。
URI をクライアントで組み立てるのは良くない(RESTでない)。
PUTやPOSTで渡すXMLをクライアントで組み立てるのは、良い。
という理解でよいですか?
田中さん
基本的には XML 文書中に含まれている URI を自分で選択して辿るのがクライアントの役割です。たとえば「私のブログのREST入門を見てください」とほかの人に伝えるときに、
・URI スキームはhttpで
・ホストは yohei-y.blogspot.com
・ポートは 80
・パスの部分は/2005/04/....html
などと URI を組み立てるためのヒントだけ与えて、実際の URI は教えてあげないなんてことはないですよね。URI をクライアント側で組み立てないというのはこれと同じです。
一方で、自分のブログを投稿するときにサーバから教えてもらった内容しか投稿できない、なんてことはないですよね。PUT や POST で渡すドキュメントはもちろんクライアントが作成します。
興味深く読ませていただきました。
理念としては理解できましたが、では実装としてどうなのかという疑問があります。
検索フォームなんかは更新とかしないのでGETで送るのが正しいのでしょうが、非常に複雑でややこしいフォームだった場合URLの文字長制限を超えてしまう可能性があります。
RFC2616では確かに
>The HTTP protocol does not place any a priori limit on the length of
a URI.
となっていますがIEだと1000とか2000文字程度です。
また受け取る側のサーバにもしっかり414なんてステータスコードがあったりします。
こういう場合に「仕様を満たしていないIEが悪い、FF使え」「Apacheの設定変えれ」とかそういうことにはいかないわけで。
実際問題としてどうなんだろう、という通りすがりの疑問でした。
コメントを投稿
<< Home