2005-04-29

REST 入門(その5) 四つの動詞 -- GET, POST, PUT, DELETE

» REST 入門 目次

前回、URI で特定できるリソースに HTTP の GET という動詞を適用して、 ある時点・条件での状態の表現を転送するのが REST だという説明をしました。 URI (名詞)に適用できる動詞は GET だけではありません。

今回は GET 以外の三つの動詞を紹介します。

前提知識

ここでは実際に稼動している REST 実装の例としてはてなブックマーク AtomAPI を使います。 はてなブックマークそのものの説明はしませんので、あらかじめご了承ください。

はてなブックマークに登録したひとつのブックマークを考えてみてください。 このひとつのブックマークエントリが、対象のリソースになります。 たとえば REST 入門の目次をブックマークしたとします。 このブックマークの URI は http://b.hatena.ne.jp/atom/edit/175062 です。 まずは GET してみましょう。

GET /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

HTTP/1.1 200 OK
Content-Type: application/x.atom+xml

<entry xmlns="http://purl.org/atom/ns#">
  <title>傭兵日記: REST 入門</title>
  <link rel="related" type="text/html"
      href="http://yohei-y.blogspot.com/2005/04/rest_23.html" />
  <link rel="alternate" type="text/html"
      href="http://b.hatena.ne.jp/yohei/20050424#175062" />
  <link rel="service.edit" type="application/x.atom+xml"
    href="http://b.hatena.ne.jp/atom/edit/175062" title="傭兵日記: REST 入門" />
  <author>
    <name>yohei</name>
  </author>
  <generator url="http://b.hatena.ne.jp/" version="0.1"
    >Hatena::Bookmark</generator>
  <issued>2005-04-24T:14:46:00+9:00</issued>
  <id>tag:hatena.ne.jp,2005:bookmark-sample-175062</id>
  <summary type="text/plain">REST の入門</summary>
</entry>

実際にはてなブックマークから GET するには認証用の X-WSSE ヘッダが必要なことに注意してください。 また、レスポンスに含まれるのは HTML ではなく XML 形式のブックマークとなります。 XML に含まれる情報で重要なのは title 要素と summary 要素になります。 summary 要素はいわゆる「コメント」です。

以下では、このブックマークエントリ(リソース)の URI に、 GET 以外の HTTP メソッドを適用してみます。

リソースを更新 -- PUT

一度は登録したけれど、つけたコメントが気に入らないので修正したいとします。 こんなときは HTTP の PUT メソッドを使います。PUT リクエストはこのようになります。

PUT /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
Content-Type: application/x.atom+xml
X-WSSE: UsernameToken Username="yohei", ...

<entry xmlns="http://purl.org/atom/ns#">
  <summary type="text/plain"
    >REST(Representational State Transfer) の入門</summary>
</entry>

PUT のレスポンスはこのようになります。

HTTP/1.1 200 OK

今、更新した URI を再度 GET することができます。

GET /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

取得される XML は、コメントが修正されたものになっているはずです。

HTTP/1.1 200 OK
Content-Type: application/x.atom+xml

<entry xmlns="http://purl.org/atom/ns#">
  <title>傭兵日記: REST 入門</title>
  <link rel="related" type="text/html"
      href="http://yohei-y.blogspot.com/2005/04/rest_23.html" />
  <link rel="alternate" type="text/html"
      href="http://b.hatena.ne.jp/yohei/20050424#175062" />
  <link rel="service.edit" type="application/x.atom+xml"
    href="http://b.hatena.ne.jp/atom/edit/175062" title="傭兵日記: REST 入門" />
  <author>
    <name>yohei</name>
  </author>
  <generator url="http://b.hatena.ne.jp/" version="0.1"
    >Hatena::Bookmark</generator>
  <issued>2005-04-24T:14:46:00+9:00</issued>
  <id>tag:hatena.ne.jp,2005:bookmark-sample-175062</id>
  <summary type="text/plain"
    >REST(Representational State Transfer) の入門</summary>
</entry>

リソースを削除 -- DELETE

ブックマークを削除したい場合は DELETE メソッドを使います。

DELETE /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

HTTP/1.1 200 OK

DELETE が成功すると、同じ URI を再度 GET することはできません。

GET /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

レスポンスは HTTP エラーになります。

HTTP/1.1 404 Not Found

リソースを新規作成 -- POST

先ほどのブックマーク、消してしまったけれどやっぱり元に戻したいとします。 そんなときは POST でブックマークリソースを新規に作成します。 でも、どの URI に POST したらよいのでしょうか。 リソースを新規に作成するわけですから、リソース自体がまだ存在せず、 したがって URI もありません。

こういう時はリソースを新規作成するためのリソースを用意します。 はてなブックマークではこのリソースの URI を PostURI と呼んでいます。 それでは POST してみましょう。

POST /atom/post HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

<entry xmlns="http://purl.org/atom/ns#">
  <link rel="related" type="text/html"
      href="http://yohei-y.blogspot.com/2005/04/rest_23.html" />
  <summary type="text/plain"
    >REST(Representational State Transfer) の入門</summary>
</entry>

正常に受け付けられると以下のようなレスポンスが返ってきます。

HTTP/1.1 201 OK
Content-Type: application/x.atom+xml
Location: http://b.hatena.ne.jp/atom/edit/xxxx

<entry xmlns="http://purl.org/atom/ns#">
  <title>傭兵日記: REST 入門</title>
  <link rel="related" type="text/html"
      href="http://yohei-y.blogspot.com/2005/04/rest_23.html" />
  <link rel="alternate" type="text/html"
      href="http://b.hatena.ne.jp/yohei/20050424#xxxx" />
  <link rel="service.edit" type="application/x.atom+xml"
    href="http://b.hatena.ne.jp/atom/edit/xxxx" title="傭兵日記: REST 入門" />
  <author>
    <name>yohei</name>
  </author>
  <generator url="http://b.hatena.ne.jp/" version="0.1"
    >Hatena::Bookmark</generator>
  <issued>2005-04-24T:17:46:00+9:00</issued>
  <id>tag:hatena.ne.jp,2005:bookmark-sample-xxxx</id>
  <summary type="text/plain"
    >REST(Representational State Transfer) の入門</summary>
</entry>

レスポンスには Location ヘッダがあります。 これが新規作成されたリソースの URI になります。

POST メソッドは、その自由度の高さから、濫用される傾向にあります。 実際には GET, PUT, DELETE で行えることも、POST でできてしまうのです。 しかし、HTTP メソッド本来の意味を考えて POST メソッドを利用するのが正しいのは言うまでもありません。 POST を使うときの経験則として、POST をリソースの新規作成にだけ使う、 というものがあります。新しいリソースを POST する、と覚えましょう。 Paul Prescod の "Common REST Mistakes" の2番がこれに該当します。

まとめ

今回の POST, PUT, DELETE と、前回の GET はある点で大きく異なります。 それは GET がリソースの状態に影響を与えないのに対して、 それ以外の三つの動詞がリソースの状態に何らかの影響を与える可能性がある点です。 このような性質を副作用(side effect)といいます。 副作用のない GET はキャッシュという大きな可能性を持つことになります。 キャッシュについては機会があれば説明しようと思います。

これまでの内容をまとめると以下のようになります。

  • GET はリソースを取得するメソッド
  • PUT はリソースを更新するメソッド
  • DELETE はリソースを削除するメソッド
  • POST はリソースを新規作成するメソッド
  • GET はリソースに副作用を与えない

REST では、リソースを操作するインターフェースにはこの四つのメソッドしかありません。 getXx() も setXx() も startXx() も createXx() もないのです。 これは REST アーキテクチャスタイルの持つ大きな制約のひとつ、 統一インターフェース(uniform interface)です。

次回は、Web の最大の特徴であるリンクと REST の関係について解説したいと思います。

[update 2005-05-22] POST と PUT についての記事を追加しました。

[update 2007-09-21] 2007年7月に Atom Publishing Protocol は標準化作業が終了しました。また、その技術解説を WEB+DB PRESS Vol.40 に書いています

5 件のコメント:

  1. POSTのときPostURIは無くてはならないものなのでしょうか?
    たとえば、
    http://xxx.xxx/bookmark/
    にPOSTすると、
    http://xxx.xxx/bookmark/xxxxxx
    と言うようなURIに新規作成されるのでは、駄目なんでしょうか?

    返信削除
  2. PostURI は何でもいいんです。nagasawa さんの例の http://xxx.xxx/bookmark/ も PostURI と呼べると思います。

    実は PostURI というのは古い Atom API 用語で、現時点での最新版では PostURI という用語は出てきません。そのかわりに、コレクションリソース(ブックマークでいえばブックマーク集のようなもの)の URI に POST することで新しいエントリが追加されるようになっています。

    返信削除
  3. このページを読んで自分の手を動かして理解するためには"X-WSSE"のところが結構大きなネックになりそうです。関連ツールの紹介があるとよいのですが。
    例えばeXeve(http://www.witha.jp/eXeries/ja/index.html)は便利です。

    返信削除
  4. なんかPostURIというのがしっくり来ません。
    PostURIにPostするのがOKなら、DeleteURIにPostすることでリソースを削除するのもOKな気がしますが。

    Postする時点ではそのリソースのURIが無いから仕方なくPostURIというものを使うのでしょうか。
    これが「仕方なく」か「そうでない」かの違いは小さくないのではないかと思います。

    例えば、PostURIが一意に定まっておらず、存在しないURIに対してPostしたら新規作成、というような実装があってもかまわないのでしょうか?

    返信削除
  5. 連投すいません。

    この4つ以外の動詞も使ってよいのでしょうか?
    HEADとかOPTIONSとかWebDAVとか。

    返信削除