RESTfulなWeb APIでリソースの一部のみ更新したい場合、なにか良い方法があるのかなと思ってちょっと調べていたのだが、これと決まった物はないらしい。
Joe Gregorioはxml:idを利用して更新する要素を指定したURIに対してPUTメソッドを実行することを提案している。
これは、このようにxml:idをふって、
<?xml version="1.0"?> <entry xmlns="http://www.w3.org/2005/Atom" xmlns:t="http://blah..."> <t:link_template ref="sub" href="http://example.org/edit/first-post/{-listjoin|;|id}"/> <title xml:id="X1">Atom-Powered Robots Run Amok</title> <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id> <updated>2003-12-13T18:30:02Z</updated> <author xml:id="X2"><name>John Doe</name></author> <content xml:id="X3">Some text.</content> <link rel="edit" href="http://example.org/edit/first-post.atom"/> </entry>
このように修正する要素のみ指定したURIに対してPUTするものである。
PUT /edit/first-post/X1;X3 Host: example.org <?xml version="1.0"?> <entry xmlns="http://www.w3.org/2005/Atom"> <title xml:id="X1">False alarm on the Atom-Powered Robots things</title> <content xml:id="X3">Sorry about that.</content> </entry>
コメント欄ではxml:idではなくXPathを使ったらとか、PATCHかPOSTを用いるべきというものや、もっとシンプルにPUT /posts/12345?partial=authorsみたいにすればといったような意見がある。
PATCHメソッドを利用した方法としてはRob Sayreが、JSON形式の独自diffをpatchする方法を紹介している。
これは、こんな感じのdiff形式であり、pathはJSONのルートからの属性のパスを配列で表して、それをvalueに対してactionの処理を行うという意味である
PATCH /my/stuff/thing HTTP/1.1 Host: example.com Content-Length: 394 Content-Type: x-application/json-sync [ {"action":"edit", "path":["x"], "value":43}, {"action":"remove", "path":["b", "d", "f"]}, {"action":"create", "path":["b", "new2"], "value":22}, {"action":"remove", "path":["h"]}, {"action":"create", "path":["i", "3"], "value":99}, {"action":"edit", "path":["n"], "value":{}}, {"action":"create", "path":["n", "new3"], "value":77}, {"action":"create", "path":["new"], "value":11} ]
で、この方式についてはRoy Fieldingも
> http://blog.mozilla.com/rob-sayre/2008/02/15/restful-partial-updates/
Damn, I knew I should have finished my blog first ... a blog wave has
started and I'm still getting into my trunks.
...YAML is a better format for contextual diffs. I think your json.sync
Re: PATCH vs multipart/byteranges vs Content-Range from Roy T. Fielding on 2008-02-16 (ietf-http-wg@w3.org from January to March 2008)
format is close, but way too verbose (we are supposed to be saving
bandwidth here, not being human-readable). Maybe I should start a
wiki for diff formats and just start registering them.
とコメントしており、YAMLのフォーマットを考えているらしいが見当たらなかった。
また、Google Data APIでは実験的にPATCHメソッドによるpartial updateを提供している。
例として以下のリクエストがあげられており実行すると、description(gd:fieldsの部分)が削除され、titleが更新される。
PATCH /myFeed/1/1/ Content-Type: application/xml <entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005' gd:fields='description'> <title>New title</title> </entry>
Joe Gregorioの方式はxml:idを使う部分を除けばシンプルで良い方法だと思うが、コメント欄で指摘されている通り、子要素をサブリソースとみなすのは良いとしても、そのコンビネーションがサブリソースなのかという疑問がある。PATCHメソッドの方式は分かりやすいのだが、既存のライブラリがPATCHメソッドに対応しているのかという問題がありそうだし、diffのフォーマットが人それぞれで統一されなさそうな気がする。