原文地址https://tools.ietf.org/html/rfc6902
1.簡介
JavaScript Object Notation (JSON) [RFC4627]是一種交換和存儲的結構化數據常見的格式。HTTP PATCH [RFC5789]方法對資源進行部分修改,擴展了超文本傳輸協議(HTTP)[RFC2616]。
JSON PATCH 是一種格式(由媒體類型"application/ json-patch+json"標識)用于表示要應用到目標JSON文檔的操作序列。它適合用于HTTP PATCH 方法。
這種格式在其他需要對JSON文檔或具有類似約束的數據結構進行部分更新的情況下也可能有用(也就是說,可以使用JSON語法將其序列化為對象或數組。)。
2.約定
關鍵詞"MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL"在本文檔中解釋為RFC 2119[RFC2119]中描述的內容。
3.文檔結構
一個JSON Patch文檔是一個JSON文檔[RFC4627]表現為一個對象數組。每個對象代表一個被應用到目標JSON文檔的操作。
下面是一個JSON Patch示例文檔,傳輸HTTP Patch請求:
PATCH /my/data HTTP/1.1
Host: example.org
Content-Length: 326
Content-Type: application/json-patch+json
If-Match: "abc123"
[
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]
針對目標JSON文檔,開始對JSON Patch進行計算。操作按照數組中出現的順序依次被應用。序列中的每個操作都應用于目標文檔;結果文檔成為下一個操作的目標。計算過程一直持續到成功地應用所有操作或者直到遇到錯誤條件。
4.操作
操作對象必須有一個“op”成員,其值表示要執行的操作。它的值必須是"add", "remove", "replace", "move", "copy", 或"test"中的一個;其他值是錯誤的。下面是每個對象的語義定義。
此外,操作對象必須有一個精確的“path”成員。值是一個包含JSON-Pointer值的字符串[RFC6901],這個值引用目標文檔(the "target location")中的一個位置執行操作。
其他操作對象成員的含義由操作定義(見下面的小節)。未被明確定義為操作成員的問題必須忽略(也就是說,操作將完成,就像未定義的成員沒有出現在對象中)。
注意,JSON對象中成員的順序并不重要; 因此,以下操作對象是等價的:
{ "op": "add", "path": "/a/b/c", "value": "foo" }
{ "path": "/a/b/c", "op": "add", "value": "foo" }
{ "value": "foo", "path": "/a/b/c", "op": "add" }
操作應用于由JSON文檔表示的數據結構,也就是說,在任何非轉義的情況下(參見RFC4627,第2.5小節) 發生。
4.1.add
“add”操作執行以下功能之一,取決于目標位置引用的內容:
- 如果目標位置指定一個數組索引,那么新值就是在指定的索引中插入數組。
- 如果目標位置指定不存在的對象成員,則將新成員添加到對象中。
- 如果目標位置指定存在的對象成員,該成員的值被替換。
- 操作對象必須包含一個“value”成員,其內容指定要添加的值。
例如:{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }
應用操作時,目標位置必須引用:
- 目標文檔的根 - 然后指定的值成為目標文檔的整個內容。
- 添加到現有對象的成員 - 然后在指定位置將提供的值添加到該對象。如果成員已經存在,則由指定值替換。
- 添加到現有數組的元素 - 因此提供的值添加到數組的指定位置。在指定索引上的任何元素都會向右側移動一個位置。指定的索引不能大于數組中元素的個數。如果-”字符用于索引數組的末尾(見[RFC6901]),這就產生將值追加到數組中的作用。
因為這個操作被設計用來增加現有的對象和數組,其目標位置通常會不存在。盡管指針的錯誤處理算法將被調用,該規范定義了“add”的錯誤處理行為忽略指針錯誤并添加指定的值。
然而,對象本身或包含它的數組需要存在,如果不是這樣的話,它仍然是一個錯誤,。以"/a/b"開始的目標位置的“add”文檔:
{ "a": { "foo": 1 } }
這不是一個錯誤,因為“a”存在,并且“b”將被添加到它的值中。
這是本文檔中的一個錯誤:
{ "q": { "bar": 2 } }
因為“a”不存在。
4.2. remove
“remove”操作刪除目標位置的值。要操作成功,目標位置必須存在。
例如: { "op": "remove", "path": "/a/b/c" }
如果從數組中刪除元素,指定索引上的任何元素都會向左移動一個位置。
4.3 . replace
"replace"操作用新值替換目標位置上的值。操作對象必須包含“value”成員,其內容指定替換值。
要操作成功,目標位置必須存在。
例如:{ "op": "replace", "path": "/a/b/c", "value": 42 }
此操作在功能上與值的“remove”操作完全相同,緊接著在相同的位置使用替換值進行“add”操作。
4.4. move
"move"操作清除指定值并添加它到目標位置。
操作對象必須包含“from"成員,它是一個包含JSON Pointer值的字符串,該值引用目標文檔中的位置以從中移動值。
要操作成功,‘’from'位置必須存在。
例如:
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" }
這個操作在功能上與在"from"位置的”remove“操作相同,緊接著在目標位置使用剛移除的值進行”add“操作。
”from“位置不能是”path“位置的真正的前綴。也就是說,不能將位置移動到其子節點中。
4.5. copy
"copy"操作復制指定位置的值到目標位置。
操作對象必須包含“from"成員,它是一個包含JSON Pointer值的字符串,該值引用目標文檔中的位置以從中復制值。
要操作成功,‘’from'位置必須存在。
例如:
{ "op": "copy", "from": "/a/b/c", "path": "/a/b/e" }
這個操作在功能上與在目標位置使用”from“成員中指定值的”add“操作相同。
4.6. test
"test"操作測試目標位置的值與指定的值相等。
操作對象必須包含“value”成員,傳達值與目標位置的值進行比較。
目標位置必須等于該值的“value”, 操作才被認為是成功的。
這里,“equal”表示目標位置的值和傳達的“value”是相同的JSON類型,并且它們被認為等于下列規則的類型:
- strings:如果被認為是相等的,它們包含相同數量的Unicode字符及其代碼點逐字節相等
- numbers:如果它們的數值相等,則被認為是相等的。
- arrays:如果它們包含相同數量的值,并且每個值可以視為等于另一個數組中相應位置的值,使用此特定類型規則的list,則被認為是相等的
- objects:如果它們包含相同數量的成員,并且如果每個成員可以被認為是等于另一對象中的成員,通過比較他們的鍵(如字符串)和它們的值(使用此特定類型規則的list),那么被認為是相等的,
- literals (false, true, and null):如果他們都是相同的,則被認為是相等的。
注意,此比較是一個邏輯比較;例如,數組的成員值之間的空格并不重要。
另外,注意對象成員序列化的順序不重要。
例如: { "op": "test", "path": "/a/b/c", "value": "foo" }
5. 錯誤處理
如果一個規范要求違反了JSON Patch文檔,或者如果一個操作不成功,那么JSON Patch文檔的計算應該終止,整個Patch文檔的應用不應被認為是成功的。
查看[RFC5789],2.2小節是關于處理錯誤的注意事項,當通過HTTP Patch方法使用JSON Patch時,包括建議使用狀態碼來表示各種條件。
注意,HTTP PATCH方法是原子性的,依據[RFC5789]。因此,以下patch會導致文檔沒有被更改(因為“test”操作會導致錯誤):
[
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "test", "path": "/a/b/c", "value": "C" }
]
6. IANA Considerations
JSON Patch文檔的互聯網媒體類型是application/json-patch+json.
類型名稱(Type name): application
子類型名稱(Subtype name): json-patch+json
必需的參數(Required parameters): none
可選的參數(Optional parameters): none
編號考量(Encoding considerations): binary
安全注意事項:參見第7節中的安全注意事項。
互操作性問題:N / A
發布說明書:
RFC 6902
使用這種媒體類型的應用程序:
操作JSON文檔的應用程序。
附加信息:
Magic number(s): N/A
文件擴展名File extension(s): .json-patch
蘋果電腦文件類型代碼Macintosh file type code(s): TEXT
個人及電子郵件地址,取系以獲取更多的信息:
保羅·c·布萊恩< pbryan@anode.ca >
用途Intended usage: COMMON
使用限制Restrictions on usage: none
作者Author: Paul C. Bryan pbryan@anode.ca
變更管理Change controller: IETF
7. Security Considerations安全性考量
該規范與JSON[RFC4627]和JSON-Pointer [RFC6901]具有相同的安全性考量。
一些老的Web瀏覽器可以強制加載一個隨意的根為數組的JSON文檔,從而導致一個包含敏感信息的JSON Patch文檔可能被暴露給攻擊者的情況,即使訪問是經過驗證的。這就是所謂的跨站點請求偽造(CSRF)攻擊 [CSRF]。
然而,這樣的瀏覽器并沒有被廣泛使用(在撰寫本文時,估計它們在不到1%的市場中使用)。盡管如此,發布者仍擔心這種攻擊,應避免使用http GET提供此類文檔。
8. 致謝
以下的人員為本規范提供了想法、反饋和措辭:
Mike Acar, Mike Amundsen, Cyrus Daboo, Paul Davis, Stefan Koegl, Murray S. Kucherawy, Dean Landolt, Randall Leeds, James Manger, Julian Reschke, James Snell, Eli Stevens, and Henry S. Thompson.
JSON Patch文檔的結構受到了XMLPatch 文檔規范的影響[RFC5261]。
9.參考文獻
9.1. 標準參考
[RFC2119] Bradner, S.,(在RFC中使用來表示需求級別的關鍵字)BCP 14,RFC2119,1997年3月。
[RFC4627] Crockford,D.,(JavaScript Object Notation (JSON)的application/json媒體類型)RFC4627,2006年7月
[RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed.,JavaScript Object Notation (JSON) Pointer",RFC 6901,2013年4月
9.2參考資料
[CSRF] Barth, A., Jackson, C., and J. Mitchell, "Robust Defenses for Cross-Site Request Forgery", ACM Conference on Computer and Communications Security, October 2008, http://seclab.stanford.edu/websec/csrf/csrf.pdf.
[RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
[RFC5261] Urpalainen, J., "An Extensible Markup Language (XML) Patch Operations Framework Utilizing XML Path Language (XPath) Selectors", RFC 5261, September 2008.
[RFC5789] Dusseault, L. and J. Snell, "PATCH Method for HTTP",RFC 5789, March 2010.
附錄a .示例
A.1. 添加對象成員(Adding an Object Member)
目標JSON文檔示例(An example target JSON document):
{ "foo": "bar"}
JSON Patch文檔(A JSON Patch document):
[
{ "op": "add", "path": "/baz", "value": "qux" }
]
生成的JSON文檔(The resulting JSON document):
{
"baz": "qux",
"foo": "bar"
}
A.2. 添加數組元素(Adding an Array Element)
目標JSON文檔示例:
{ "foo": [ "bar", "baz" ] }
JSON Patch文檔: [ { "op": "add", "path": "/foo/1", "value": "qux" } ]
生成的JSON文檔: { "foo": [ "bar", "qux", "baz" ] }
A.3. 移除一個對象成員(Removing an Object Member)
目標JSON文檔示例:
{
"baz": "qux",
"foo": "bar"
}
JSON Patch文檔:
[ { "op": "remove", "path": "/baz" } ]
生成的JSON文檔: { "foo": "bar" }
A.4. 移除一個數組元素Removing an Array Element
目標JSON文檔示例:
{ "foo": [ "bar", "qux", "baz" ] }
JSON Patch文檔:
[
{ "op": "remove", "path": "/foo/1" }
]
生成的JSON文檔:
{ "foo": [ "bar", "baz" ] }
A.5. 替換值(Replacing a Value)
目標JSON文檔示例:
{
"baz": "qux",
"foo": "bar"
}
JSON Patch文檔:
[
{ "op": "replace", "path": "/baz", "value": "boo" }
]
生成的JSON文檔:
{
"baz": "boo",
"foo": "bar"
}
A.6. 移動值(Moving a Value)
目標JSON文檔示例:
{
"foo": {
"bar": "baz",
"waldo": "fred"
},
"qux": {
"corge": "grault"
}
}
JSON Patch文檔:
[
{ "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }
]
生成的JSON文檔:
{
"foo": {
"bar": "baz"
},
"qux": {
"corge": "grault",
"thud": "fred"
}
}
A.7. 移動數組元素(Moving an Array Element)
目標JSON文檔示例:
{ "foo": [ "all", "grass", "cows", "eat" ] }
JSON Patch文檔:
[
{ "op": "move", "from": "/foo/1", "path": "/foo/3" }
]
生成的JSON文檔:
{ "foo": [ "all", "cows", "eat", "grass" ] }
A.8. 測試值:成功(Testing a Value: Success)
目標JSON文檔示例:
{
"baz": "qux",
"foo": [ "a", 2, "c" ]
}
將計算成功的JSON Patch文檔:
[
{ "op": "test", "path": "/baz", "value": "qux" },
{ "op": "test", "path": "/foo/1", "value": 2 }
]
A.9. 測試值:錯誤(Testing a Value: Error)
目標JSON文檔示例:
{ "baz": "qux" }
將導致錯誤狀態的JSON Patch文檔:
[
{ "op": "test", "path": "/baz", "value": "bar" }
]
A.10. 添加嵌套成員對象(Adding a Nested Member Object)
目標JSON文檔示例:
{ "foo": "bar" }
JSON Patch文檔:
[
{ "op": "add", "path": "/child", "value": { "grandchild": { } } }
]
生成的JSON文檔:
{
"foo": "bar",
"child": {
"grandchild": {
}
}
}
A.11. 忽略無法識別的元素(Ignoring Unrecognized Elements)
目標JSON文檔示例:
{ "foo": "bar" }
JSON Patc文檔:
[
{ "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }
]
生成的JSON文檔:
{
"foo": "bar",
"baz": "qux"
}
A.12. 添加到不存在的目標(Adding to a Nonexistent Target)
目標JSON文檔示例:
{ "foo": "bar" }
JSON Patc文檔:
[
{ "op": "add", "path": "/baz/bat", "value": "qux" }
]
這個JSON Patch文檔,應用于目標JSON文檔上面,會導致一個錯誤(因此,它不會被應用),因為“add”操作的目標位置,既不引用文檔的根,也不是現有對象的成員,也不是現有數組的成員。
A.13. 無效的JSON Patch文檔(Invalid JSON Patch Document)
JSON Patc文檔:
[
{ "op": "add", "path": "/baz", "value": "qux", "op": "remove" }
]
這個JSON Patch文件不能被視為一個“add”操作,因為它包含后面的"op":"remove"元素。JSON要求對象成員的名稱是具有唯一的“SHOULD”要求,并且副本沒有的標準錯誤處理。
A.14. 轉義排序( Escape Ordering)
目標JSON文檔示例:
{
"/": 9,
"~1": 10
}
JSON Patc文檔:
[
{"op": "test", "path": "/~01", "value": 10}
]
生成的JSON文檔:
{
"/": 9,
"~1": 10
}
A.15. 比較字符串和數字(Comparing Strings and Numbers)
目標JSON文檔示例:
{
"/": 9,
"~1": 10
}
JSON Patc文檔:
[
{"op": "test", "path": "/~01", "value": "10"}
]
這會導致一個錯誤,因為測試失敗了。文檔的值是數值,而被測試值是一個字符串。
A.16. 添加數組值(Adding an Array Value)
目標JSON文檔示例:
{ "foo": ["bar"] }
JSON Patc文檔:
[
{ "op": "add", "path": "/foo/-", "value": ["abc", "def"] }
]
生成的JSON文檔:
{ "foo": ["bar", ["abc", "def"]] }
作者的地址
Paul C. Bryan (editor)
Salesforce.com
Phone: +1 604 783 1481
EMail: pbryan@anode.ca
Mark Nottingham (editor)
Akamai
EMail: mnot@mnot.net