JSON PointerとJSON Patch

# JSON PointerとJSON Patch
AWSのAPI Gatewayを[試していたところ](http://qiita.com/taknuki/items/dd47d1c6d4190b52df9a)、API(API Gatewayの)でJSON Patchなるものを使うことになりました。よくわからんちんでしたが、RFCが出ているということなので読んでみました。以下メモ。

## RFC
* [JavaScript Object Notation (JSON) Pointer](https://tools.ietf.org/html/rfc6901)
* [JavaScript Object Notation (JSON) Patch](https://tools.ietf.org/html/rfc6902)

## JSON Pointer
### overview
* JSON PointerはJSOCドキュメント中の位置を表す仕様。XMLのXPathみたいなもの。
* ABNFで書くと
    * json-pointer = `*( "/" reference-token )`
    * reference-token = `*( unescaped / escaped )`
    * unescaped = `%x00-2E / %x30-7D / %x7F-10FFFF`
        * つまり`%x2F('/')`と`%x7E('~')`以外
    * escaped = "~" ( "0" / "1" )
        * 「~0」が'~'
        * 「~1」が'/'
        * エスケープを外す際は「~1」から「~0」の順に行う。
* JSON Patch等で使われる際はJSONドキュメント中に書くので、JSONとしてのエスケープ(ダブルクォート等)も必要になる。
* ざっくり言えば、オブジェクトのキーを`/`区切りで並べたもの。
* 配列の場合は0始まりの添え字まで指定できる。
    * `/hoge/fuga/0`, `/hoge/fuga/1`, ...といったように。
    * `-`を使うと、末尾の添え字+1という意味になる。  
      次に述べるJSON Patchで最後に挿入といったことを表すために使用する。

### examples
こんな感じ

```pointer_sample.json
{
  "hoge" : "this is '/hoge'",
  "" : "this is '/'",
  "foo/bar" : "this is '/foo~1bar'",
  "foo~bar" : "this is '/foo~0bar'",
  "fuga" : [
    "this is /fuga/0",
    "this is /fuga/1"
  ],
  "foo" : {
    "bar" : "this is '/foo/bar'" 
  }
}
```

## JSON Patch
### overview
* JSON PatchはJSONドキュメントに対する追加・更新・削除といったオペレーションを表現する。
* JSON Patchはそれ自体がJSONドキュメントとして表現され、「対象のJSONドキュメントに対して実行されるオペレーション」を表すオブジェクトの配列である。
* オペレーションは配列のインデックスの順にシーケンシャルに実行される。
* オペレーションを表すオブジェクトは操作を表す**`op`**メンバと操作対象を表す**`path`**メンバを必ず含む。
    * `op`メンバは次のうちから一つ
        * `add`
        * `remove`
        * `replace`
        * `move`
        * `copy`
        * `test`
    * `path`メンバは上に書いたJSON Pointer
* HTTPのPATCHメソッドと一緒にご利用ください。
    * [RFC5789](https://tools.ietf.org/html/rfc5789)によると、PATCHメソッドはatomicに実行される必要があるので、オペレーションが一つでも失敗したら全てロールバックしないといけない。
* メディアタイプは`application/json-patch+json`

### add
**`value`**メンバが必須(JSON Value)

* `path`が配列のインデックスを表している場合、`value`が指定されたインデックスに挿入される。
    * この場合、指定されたインデックスに元々入っていた要素およびそれより後ろに入っていた要素は後ろにずれる。
    * 末尾に入れる場合は上に書いた`-`を使う。`"/array/-"`みたいに。
* `path`が存在しないオブジェクトを表している場合、`value`が指定されたオブジェクトとして追加される。
    * ただし、`/a`というJSON Pointerが存在しているオブジェクトを指していない場合、`/a/b`という`path`はinvalidになる。親が存在していることが前提ということか。
* `path`が存在しているオブジェクトを表している場合、`value`の値に変更される。「add」だけどupdate?
* example

```before.json
{ "hoge" : "fuga", "ary" : [ "0", "1" ], "obj" : { "key" : "value" } }
```
```add1.json
{ "op": "add", "path": "/foo", "value": "bar" }
```
```after1.json
{ "hoge" : "fuga", "ary" : [ "0", "1" ], "obj" : { "key" : "value" }, "foo" : "bar" }
```
```add2.json
{ "op": "add", "path": "/ary/-", "value": "2" }
```
```after2.json
{ "hoge" : "fuga", "ary" : [ "0", "1", "2" ], "obj" : { "key" : "value" } }
```
```add3.json
{ "op": "add", "path": "/obj/newkey", "value": "newvalue" }
```
```after3.json
{ "hoge" : "fuga", "ary" : [ "0", "1" ], "obj" : { "key" : "value" , "newkey" : "newvalue"} }
```

### remove
* `path`で指定された要素を削除
* `path`で指定された要素が存在しない場合はエラー
* 配列の要素を削除した場合、削除した要素より後ろの要素が前にずれる。
* example

```before.json
{ "hoge" : "fuga", "foo" : "bar" }
```
```remove.json
{ "op": "remove", "path": "/hoge" }
```
```after.json
{ "foo" : "bar" }
```

### replace
**`value`**メンバが必須(JSON Value)

* `remove`からの`add`と同じ動作とRFCに書いてある。
* `path`が配列以外を指している場合は(```remove```せずに)```add```するだけと同じ(どちらもupdate)だと思われるが、配列の要素の場合は```add```だとinsertになる一方で```replace```だとupdateになる。
* example

```before.json
{ "hoge" : "fuga" }
```
```replace.json
{ "op": "replace", "path": "/hoge", "value": [ "foo", "bar" ] }
```
```after.json
{ "hoge" : [ "foo", "bar" ] }
```

### move
**`from`**メンバが必須(JSON Pointer)

* `from`で指定された位置にある要素を`path`で指定された位置に移動する。
* `from`で指定された要素が存在しない場合はエラー
* `from`で指定した位置は`path`で指定した位置よりも内側にないといけない、というか自分を自分の子供にすることはできない。
* example

```before.json
{ "hoge" : "fuga" }
```
```move.json
{ "op": "move", "path": "/foo", "from": "/hoge" }
```
```after.json
{ "foo" : "fuga" }
```

### copy
**`from`**メンバが必須(JSON Pointer)

* `from`で指定された位置にある要素を`path`で指定された位置にコピーする。
* `from`で指定された要素が存在しない場合はエラー
* example

```before.json
{ "hoge" : "fuga" }
```
```copy.json
{ "op": "copy", "path": "/foo", "from": "/hoge" }
```
```after.json
{ "hoge" : "fuga", "foo" : "fuga" }
```

### test
**`value`**メンバが必須(JSON Value)

* `path`で指定された位置にある要素の値が、`value`の値と一致するか検査する。
* 一致するかの基準は次の通り(リテラル・ナンバー・文字列は省略)
    * 配列: 配列の要素数が一致し、各要素もそれぞれ一致すること。
    * オブジェクト: 同じキーを持ち、各キーに対応する値が一致すること。
    * JSONとして一致するかなので、下記はそれぞれ一致。
        * `[a,b]`と`[a, b]`
        * `{"a":"fuga", "b":"hoge"}`と`{"b":"hoge", "a":"fuga"}`
* example

```target.json```
{ "hoge" : "fuga" }
```
```test_sucsess.json
{ "op": "test", "path": "/hoge", "value": "fuga" }
```
```test_error.json
{ "op": "test", "path": "/hoge", "value": "bar" }
```

## 所感
* REST APIで操作対象とするリソースをJSON Schemaで公開して、それに対する操作をJSON Patchで受け付けるみたいにするといいかも。
* やりすぎるとSOAPみたいになるかも。
* オブジェクトのやり取りを志向するのではなく、実装とは独立した抽象的なリソースの仕様として使うのが良いか。
* JSON Patch形式でJSONのdiff取ってくれるツール欲しい。