てきとうなメモ

本の感想とか技術メモとか

partial update

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
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.

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)

とコメントしており、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のフォーマットが人それぞれで統一されなさそうな気がする。