原文地址https://tools.ietf.org/html/rfc6902
JavaScript Object Notation (JSON) [RFC4627]是一种交换和存储的结构化数据常见的格式。HTTP PATCH [RFC5789]方法对资源进行部分修改,扩展了超文本传输协议(HTTP)[RFC2616]。
JSON PATCH 是一种格式(由媒体类型”application/ json-patch+json”标识)用于表示要应用到目标JSON文档的操作序列。它适合用于HTTP PATCH 方法。
这种格式在其他需要对JSON文档或具有类似约束的数据结构进行部分更新的情况下也可能有用(也就是说,可以使用JSON语法将其序列化为对象或数组。)。
关键词”MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL”在本文档中解释为RFC 2119[RFC2119]中描述的内容。
一个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进行计算。操作按照数组中出现的顺序依次被应用。序列中的每个操作都应用于目标文档;结果文档成为下一个操作的目标。计算过程一直持续到成功地应用所有操作或者直到遇到错误条件。
操作对象必须有一个“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小节) 发生。
“add”操作执行以下功能之一,取决于目标位置引用的内容:
例如:{ “op”: “add”, “path”: “/a/b/c”, “value”: [ “foo”, “bar” ] }
应用操作时,目标位置必须引用:
因为这个操作被设计用来增加现有的对象和数组,其目标位置通常会不存在。尽管指针的错误处理算法将被调用,该规范定义了“add”的错误处理行为忽略指针错误并添加指定的值。
然而,对象本身或包含它的数组需要存在,如果不是这样的话,它仍然是一个错误,。以”/a/b”开始的目标位置的“add”文档:
{ “a”: { “foo”: 1 } }
这不是一个错误,因为“a”存在,并且“b”将被添加到它的值中。
这是本文档中的一个错误:
{ “q”: { “bar”: 2 } }
因为“a”不存在。
“remove”操作删除目标位置的值。要操作成功,目标位置必须存在。
例如: { “op”: “remove”, “path”: “/a/b/c” }
如果从数组中删除元素,指定索引上的任何元素都会向左移动一个位置。
“replace”操作用新值替换目标位置上的值。操作对象必须包含“value”成员,其内容指定替换值。
要操作成功,目标位置必须存在。
例如:{ “op”: “replace”, “path”: “/a/b/c”, “value”: 42 }
此操作在功能上与值的“remove”操作完全相同,紧接着在相同的位置使用替换值进行“add”操作。
“move”操作清除指定值并添加它到目标位置。
操作对象必须包含“from”成员,它是一个包含JSON Pointer值的字符串,该值引用目标文档中的位置以从中移动值。
要操作成功,‘’from’位置必须存在。
例如:
{ “op”: “move”, “from”: “/a/b/c”, “path”: “/a/b/d” }
这个操作在功能上与在”from”位置的”remove“操作相同,紧接着在目标位置使用刚移除的值进行”add“操作。
”from“位置不能是”path“位置的真正的前缀。也就是说,不能将位置移动到其子节点中。
“copy”操作复制指定位置的值到目标位置。
操作对象必须包含“from”成员,它是一个包含JSON Pointer值的字符串,该值引用目标文档中的位置以从中复制值。
要操作成功,‘’from’位置必须存在。
例如:
{ “op”: “copy”, “from”: “/a/b/c”, “path”: “/a/b/e” }
这个操作在功能上与在目标位置使用”from“成员中指定值的”add“操作相同。
“test”操作测试目标位置的值与指定的值相等。
操作对象必须包含“value”成员,传达值与目标位置的值进行比较。
目标位置必须等于该值的“value”, 操作才被认为是成功的。
这里,“equal”表示目标位置的值和传达的“value”是相同的JSON类型,并且它们被认为等于下列规则的类型:
注意,此比较是一个逻辑比较;例如,数组的成员值之间的空格并不重要。
另外,注意对象成员序列化的顺序不重要。
例如: { “op”: “test”, “path”: “/a/b/c”, “value”: “foo” }
如果一个规范要求违反了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” }
]
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·布莱恩< [email protected] >
用途Intended usage: COMMON
使用限制Restrictions on usage: none
作者Author: Paul C. Bryan [email protected]
变更管理Change controller: IETF
该规范与JSON[RFC4627]和JSON-Pointer [RFC6901]具有相同的安全性考量。
一些老的Web浏览器可以强制加载一个随意的根为数组的JSON文档,从而导致一个包含敏感信息的JSON Patch文档可能被暴露给攻击者的情况,即使访问是经过验证的。这就是所谓的跨站点请求伪造(CSRF)攻击 [CSRF]。
然而,这样的浏览器并没有被广泛使用(在撰写本文时,估计它们在不到1%的市场中使用)。尽管如此,发布者仍担心这种攻击,应避免使用http GET提供此类文档。
以下的人员为本规范提供了想法、反馈和措辞:
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]。
[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月
[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.
目标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”
}
目标JSON文档示例:
{ “foo”: [ “bar”, “baz” ] }
JSON Patch文档: [ { “op”: “add”, “path”: “/foo/1”, “value”: “qux” } ]
生成的JSON文档: { “foo”: [ “bar”, “qux”, “baz” ] }
目标JSON文档示例:
{
“baz”: “qux”,
“foo”: “bar”
}
JSON Patch文档:
[ { “op”: “remove”, “path”: “/baz” } ]
生成的JSON文档: { “foo”: “bar” }
目标JSON文档示例:
{ “foo”: [ “bar”, “qux”, “baz” ] }
JSON Patch文档:
[
{ “op”: “remove”, “path”: “/foo/1” }
]
生成的JSON文档:
{ “foo”: [ “bar”, “baz” ] }
目标JSON文档示例:
{
“baz”: “qux”,
“foo”: “bar”
}
JSON Patch文档:
[
{ “op”: “replace”, “path”: “/baz”, “value”: “boo” }
]
生成的JSON文档:
{
“baz”: “boo”,
“foo”: “bar”
}
目标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”
}
}
目标JSON文档示例:
{ “foo”: [ “all”, “grass”, “cows”, “eat” ] }
JSON Patch文档:
[
{ “op”: “move”, “from”: “/foo/1”, “path”: “/foo/3” }
]
生成的JSON文档:
{ “foo”: [ “all”, “cows”, “eat”, “grass” ] }
目标JSON文档示例:
{
"baz": "qux",
"foo": [ "a", 2, "c" ]
}
将计算成功的JSON Patch文档:
[
{ “op”: “test”, “path”: “/baz”, “value”: “qux” },
{ “op”: “test”, “path”: “/foo/1”, “value”: 2 }
]
目标JSON文档示例:
{ “baz”: “qux” }
将导致错误状态的JSON Patch文档:
[
{ “op”: “test”, “path”: “/baz”, “value”: “bar” }
]
目标JSON文档示例:
{ "foo": "bar" }
JSON Patch文档:
[
{ “op”: “add”, “path”: “/child”, “value”: { “grandchild”: { } } }
]
生成的JSON文档:
{
“foo”: “bar”,
“child”: {
“grandchild”: {
}
}
}
目标JSON文档示例:
{ "foo": "bar" }
JSON Patc文档:
[
{ “op”: “add”, “path”: “/baz”, “value”: “qux”, “xyz”: 123 }
]
生成的JSON文档:
{
“foo”: “bar”,
“baz”: “qux”
}
目标JSON文档示例:
{ "foo": "bar" }
JSON Patc文档:
[
{ “op”: “add”, “path”: “/baz/bat”, “value”: “qux” }
]
这个JSON Patch文档,应用于目标JSON文档上面,会导致一个错误(因此,它不会被应用),因为“add”操作的目标位置,既不引用文档的根,也不是现有对象的成员,也不是现有数组的成员。
JSON Patc文档:
[
{ "op": "add", "path": "/baz", "value": "qux", "op": "remove" }
]
这个JSON Patch文件不能被视为一个“add”操作,因为它包含后面的”op”:”remove”元素。JSON要求对象成员的名称是具有唯一的“SHOULD”要求,并且副本没有的标准错误处理。
目标JSON文档示例:
{
“/”: 9,
“~1”: 10
}
JSON Patc文档:
[
{“op”: “test”, “path”: “/~01”, “value”: 10}
]
生成的JSON文档:
{
“/”: 9,
“~1”: 10
}
目标JSON文档示例:
{
“/”: 9,
“~1”: 10
}
JSON Patc文档:
[
{“op”: “test”, “path”: “/~01”, “value”: “10”}
]
这会导致一个错误,因为测试失败了。文档的值是数值,而被测试值是一个字符串。
目标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: [email protected]
Mark Nottingham (editor)
Akamai
EMail: [email protected]