RFC 6902

JavaScript Object Notation (JSON) Patch

πŸ“… published April 2013, from ietf

JavaScript Object Notation (JSON) Patch πŸŽ€

Okay bestie, here's the title block first πŸ’… This one is RFC 6902, and it's a Standards Track doc from April 2013. The authors are P. Bryan, Ed. at Salesforce.com and M. Nottingham, Ed. at Akamai. It's published under ISSN 2070-1721. The title block doesn't list anything this RFC obsoletes or updates, so there's nothing to chase there πŸ¦‹

Abstract ✨

JSON Patch is a JSON document structure for describing a list of operations to run on a JavaScript Object Notation (JSON) document. It's built to work with the HTTP PATCH method 🌸 Patch documents are identified by the media type application/json-patch+json.

Status of This Memo πŸ“œ

This is an Internet Standards Track document πŸ‘‘

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It went through public review and got approved for publication by the Internet Engineering Steering Group (IESG). If you want more on Internet Standards, check out Section 2 of RFC 5741 🧚

Info about the current status of this document, any errata, and how to send feedback is at http://www.rfc-editor.org/info/rfc6902.

Copyright (c) 2013 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info), as they stand on the publication date. Please read these carefully, because they spell out your rights and restrictions for this document 🫢 Code Components pulled out of this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Simplified BSD License.

Table of Contents πŸ—ΊοΈ

1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
2.  Conventions  . . . . . . . . . . . . . . . . . . . . . . . . .  3
3.  Document Structure . . . . . . . . . . . . . . . . . . . . . .  3
4.  Operations . . . . . . . . . . . . . . . . . . . . . . . . . .  4
  4.1.  add  . . . . . . . . . . . . . . . . . . . . . . . . . . .  4
  4.2.  remove . . . . . . . . . . . . . . . . . . . . . . . . . .  6
  4.3.  replace  . . . . . . . . . . . . . . . . . . . . . . . . .  6
  4.4.  move . . . . . . . . . . . . . . . . . . . . . . . . . . .  6
  4.5.  copy . . . . . . . . . . . . . . . . . . . . . . . . . . .  7
  4.6.  test . . . . . . . . . . . . . . . . . . . . . . . . . . .  7
5.  Error Handling . . . . . . . . . . . . . . . . . . . . . . . .  8
6.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . .  9
7.  Security Considerations  . . . . . . . . . . . . . . . . . . . 10
8.  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 10
9.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 10
  9.1.  Normative References . . . . . . . . . . . . . . . . . . . 10
  9.2.  Informative References . . . . . . . . . . . . . . . . . . 10
Appendix A.  Examples  . . . . . . . . . . . . . . . . . . . . . . 12
  A.1.  Adding an Object Member  . . . . . . . . . . . . . . . . . 12
  A.2.  Adding an Array Element  . . . . . . . . . . . . . . . . . 12
  A.3.  Removing an Object Member  . . . . . . . . . . . . . . . . 12
  A.4.  Removing an Array Element  . . . . . . . . . . . . . . . . 13
  A.5.  Replacing a Value  . . . . . . . . . . . . . . . . . . . . 13
  A.6.  Moving a Value . . . . . . . . . . . . . . . . . . . . . . 14
  A.7.  Moving an Array Element  . . . . . . . . . . . . . . . . . 14
  A.8.  Testing a Value: Success . . . . . . . . . . . . . . . . . 15
  A.9.  Testing a Value: Error . . . . . . . . . . . . . . . . . . 15
  A.10. Adding a Nested Member Object  . . . . . . . . . . . . . . 15
  A.11. Ignoring Unrecognized Elements . . . . . . . . . . . . . . 16
  A.12. Adding to a Nonexistent Target . . . . . . . . . . . . . . 16
  A.13. Invalid JSON Patch Document  . . . . . . . . . . . . . . . 17
  A.14. ~ Escape Ordering  . . . . . . . . . . . . . . . . . . . . 17
  A.15. Comparing Strings and Numbers  . . . . . . . . . . . . . . 17
  A.16. Adding an Array Value  . . . . . . . . . . . . . . . . . . 18

1. Introduction ✨

JavaScript Object Notation (JSON) [RFC4627] is a popular format for swapping and storing structured data πŸ’– HTTP PATCH [RFC5789] extends the Hypertext Transfer Protocol (HTTP) [RFC2616] with a method for making partial changes to resources, which is a super useful trick.

JSON Patch is a format (identified by the media type "application/json-patch+json") for describing a list of operations to run on a target JSON document. It's built to work with the HTTP PATCH method πŸ¦‹

This format can also come in handy in other situations where you need partial updates to a JSON document, or to some other data structure with similar rules (meaning it can be serialized as an object or an array using the JSON grammar) 🌈

2. Conventions πŸ“–

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [RFC2119] πŸŽ€

3. Document Structure 🧩

A JSON Patch document is a JSON [RFC4627] document that represents an array of objects. Each object stands for one operation to apply to the target JSON document πŸ’œ

Here's an example JSON Patch document, sent in an HTTP PATCH request πŸ‘€

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" }
]

Evaluation starts against a target JSON document πŸ”₯ Operations run one after another, in the order they show up in the array. Each operation gets applied to the target document, and the result becomes the target for the next operation. Evaluation keeps going until every operation has been applied successfully, or until an error condition shows up πŸ™ˆ

4. Operations 🌸

Operation objects MUST have exactly one "op" member, and its value says which operation to perform. That value MUST be one of "add", "remove", "replace", "move", "copy", or "test". Any other value is an error. Each operation has its own semantics, defined below πŸ’…

Operation objects MUST also have exactly one "path" member. That member's value is a string holding a JSON-Pointer value [RFC6901] that points to a location inside the target document (the "target location") where the operation happens ✨

The meanings of the other operation object members are set by each operation (see the subsections below). Members that aren't explicitly defined for the operation in question MUST be ignored. In other words, the operation completes as if the undefined member never showed up in the object 🫢

Member order in JSON objects doesn't matter, so these operation objects are all equivalent πŸ“

{ "op": "add", "path": "/a/b/c", "value": "foo" }
{ "path": "/a/b/c", "op": "add", "value": "foo" }
{ "value": "foo", "path": "/a/b/c", "op": "add" }

Operations act on the data structures that a JSON document represents, which means they run after any unescaping (see [RFC4627], Section 2.5) has happened 🌈

4.1. add πŸ¦‹

The "add" operation does one of the following things, depending on what the target location points at:

  • If the target location specifies an array index, a new value gets inserted into the array at that index.
  • If the target location specifies an object member that doesn't exist yet, a new member gets added to the object.
  • If the target location specifies an object member that already exists, that member's value gets replaced.

The operation object MUST contain a "value" member whose content is the value to add πŸ’–

For example:

{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }

When the operation is applied, the target location MUST reference one of these:

  • The root of the target document. The specified value then becomes the entire content of the target document.
  • A member to add to an existing object. The supplied value gets added to that object at the indicated location. If the member already exists, the specified value replaces it.
  • An element to add to an existing array. The supplied value gets added to the array at the indicated location, and any elements at or above the specified index shift one position to the right. The specified index MUST NOT be greater than the number of elements in the array. If the "-" character is used to index the end of the array (see [RFC6901]), the value gets appended to the array 🧚

Since this operation is built to add to existing objects and arrays, its target location often won't exist yet. The pointer's error handling algorithm gets invoked in that case, but this specification defines the error handling for "add" pointers to ignore that error and add the value as specified πŸ‘‘

The object itself, or an array containing it, does need to exist, though. If it doesn't, that's an error. For example, an "add" with a target location of "/a/b", starting from this document:

{ "a": { "foo": 1 } }

is not an error, because "a" exists and "b" will be added to its value. In this document, though, it IS an error:

{ "q": { "bar": 2 } }

because "a" doesn't exist πŸ™ˆ

Quick reminder: the parent has to exist before you can add to it. "add" can create the last piece, but not the whole path. 🫠

4.2. remove πŸ—‘οΈ

The "remove" operation removes the value at the target location πŸ’€

The target location MUST exist for the operation to succeed.

For example:

{ "op": "remove", "path": "/a/b/c" }

If you remove an element from an array, any elements above the specified index shift one position to the left 🌸

4.3. replace πŸ”

The "replace" operation swaps the value at the target location for a new one. The operation object MUST contain a "value" member whose content is the replacement value πŸ’œ

The target location MUST exist for the operation to succeed.

For example:

{ "op": "replace", "path": "/a/b/c", "value": 42 }

Functionally, this operation is identical to a "remove" operation on a value, immediately followed by an "add" operation at the same location with the replacement value. It's basically a remove and add combo in one move πŸŽ€

4.4. move 🚚

The "move" operation removes the value at a specified location and adds it to the target location ✨

The operation object MUST contain a "from" member. That member is a string holding a JSON Pointer value, and it points to the location in the target document to move the value from πŸ¦‹

The "from" location MUST exist for the operation to succeed.

For example:

{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" }

Functionally, this operation is identical to a "remove" operation on the "from" location, immediately followed by an "add" operation at the target location with the value that was just removed 🌈

The "from" location MUST NOT be a proper prefix of the "path" location. In other words, you can't move a location into one of its own children πŸ™…β€β™€οΈ

4.5. copy πŸ“‹

okay so "copy" grabs whatever value lives at a spot in the doc and drops a copy at a new spot. the original stays right where it is 🫢

the operation object MUST contain a "from" member, which is a string holding a JSON Pointer that points to the spot in the target document you're copying from. 🎯

the "from" location MUST exist for the operation to be successful. no phantom values allowed bestie πŸ’€

for example:

{ "op": "copy", "from": "/a/b/c", "path": "/a/b/e" }

and honestly? this is functionally identical to an "add" operation at the target location, using the value from the "from" member. it's giving déjà vu but make it efficient ✨

4.6. test πŸ§ͺ

"test" is the vibe check of the whole patch πŸ’… it checks that the value at the target location is equal to a value you specify.

the operation object MUST contain a "value" member that carries the value you want to compare against the target location's value.

the target location MUST be equal to the "value" value for the operation to count as successful. if it's not a match, it's not a match πŸ™ˆ

now, "equal" here has a specific meaning. the value at the target location and the value in "value" have to be the same JSON type, AND they have to pass the rule for that type:

  • strings: equal if they have the same number of Unicode characters and their code points are byte-by-byte equal. πŸ”€
  • numbers: equal if their values are numerically equal. πŸ”’
  • arrays: equal if they hold the same number of values, and each value can be considered equal to the value at the matching position in the other array, using this same list of type-specific rules. πŸŽ€
  • objects: equal if they have the same number of members, and each member can be considered equal to a member in the other object, by comparing their keys (as strings) and their values (using this same list of type-specific rules). 🧚
  • literals (false, true, and null): equal if they are the same. βœ…

the comparison is a logical one, so e.g., whitespace between the member values of an array is not significant. the serialization doesn't matter, just the meaning πŸ’œ

also, ordering of the serialization of object members is not significant. so {"a":1,"b":2} and {"b":2,"a":1} are, lowkey, the same girl πŸ’–

for example:

{ "op": "test", "path": "/a/b/c", "value": "foo" }

5. Error Handling 🚨

okay listen up, this part is serious 😭 if a normative requirement is violated by a JSON Patch document, OR if an operation isn't successful, evaluation of the JSON Patch document SHOULD terminate, and application of the entire patch document SHALL NOT be deemed successful. no partial wins, periodt πŸ’…

see [RFC5789], Section 2.2 for considerations on handling errors when JSON Patch is used with the HTTP PATCH method. it also has suggested status codes for indicating various conditions πŸ¦‹

note that the HTTP PATCH method is atomic, as per [RFC5789]. so the patch below would result in NO changes being made to the document at all, because the "test" operation errors out 🫠

[
  { "op": "replace", "path": "/a/b/c", "value": 42 },
  { "op": "test", "path": "/a/b/c", "value": "C" }
]

all or nothing, bestie. that's the energy 🌈


6. IANA Considerations 🏷️

the Internet media type for a JSON Patch document is application/json-patch+json. here's the registration template, in full:

Type name:  application

Subtype name:  json-patch+json

Required parameters:  none

Optional parameters:   none

Encoding considerations:  binary

Security considerations:
   See Security Considerations in Section 7.

Interoperability considerations:  N/A

Published specification:
   RFC 6902

Applications that use this media type:
   Applications that manipulate JSON documents.

Additional information:

   Magic number(s):  N/A

   File extension(s):  .json-patch

   Macintosh file type code(s):  TEXT

Person & email address to contact for further information:
   Paul C. Bryan <pbryan@anode.ca>

Intended usage:  COMMON

Restrictions on usage:  none

Author:  Paul C. Bryan <pbryan@anode.ca>

Change controller:  IETF

7. Security Considerations πŸ”

this spec has the same security considerations as JSON [RFC4627] and JSON-Pointer [RFC6901]. so it inherits that homework too πŸ“š

now, the spicy part. a few older Web browsers can be coerced into loading an arbitrary JSON document whose root is an array 😱 which means a JSON Patch document containing sensitive information could end up exposed to attackers, EVEN IF access is authenticated. this is known as a Cross-Site Request Forgery (CSRF) attack [CSRF]. literally terrifying, take it seriously πŸ’€

BUT, the good news: such browsers aren't widely used. at the time of writing, it's estimated they're used in less than 1% of the market. still, publishers who are concerned about this attack are advised to avoid making such documents available with HTTP GET. ngl that's a pretty clean fix πŸ›‘οΈ


8. Acknowledgements 🫢

these individuals contributed ideas, feedback and wording to this specification, and they are absolutely iconic for it πŸ‘‘

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.

and the structure of a JSON Patch document was influenced by the XML Patch document specification [RFC5261]. the way that the XML world inspired this? main character energy πŸŽ€


9. References πŸ“š

9.1. Normative References

  • [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
  • [RFC4627] Crockford, D., "The application/json Media Type for JavaScript Object Notation (JSON)", RFC 4627, July 2006.
  • [RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., "JavaScript Object Notation (JSON) Pointer", RFC 6901, April 2013.

9.2. Informative References

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

Appendix A. Examples πŸŽ€

A.1. Adding an Object Member 🌸

An example target JSON document:

{ "foo": "bar"}

A JSON Patch document:

[
  { "op": "add", "path": "/baz", "value": "qux" }
]

The resulting JSON document:

{
  "baz": "qux",
  "foo": "bar"
}

A.2. Adding an Array Element 🌸

An example target JSON document:

{ "foo": [ "bar", "baz" ] }

A JSON Patch document:

[
  { "op": "add", "path": "/foo/1", "value": "qux" }
]

The resulting JSON document:

{ "foo": [ "bar", "qux", "baz" ] }

A.3. Removing an Object Member πŸ—‘οΈ

An example target JSON document:

{
  "baz": "qux",
  "foo": "bar"
}

A JSON Patch document:

[
  { "op": "remove", "path": "/baz" }
]

The resulting JSON document:

{ "foo": "bar" }

A.4. Removing an Array Element πŸ—‘οΈ

An example target JSON document:

{ "foo": [ "bar", "qux", "baz" ] }

A JSON Patch document:

[
  { "op": "remove", "path": "/foo/1" }
]

The resulting JSON document:

{ "foo": [ "bar", "baz" ] }

A.5. Replacing a Value πŸ”

An example target JSON document:

{
  "baz": "qux",
  "foo": "bar"
}

A JSON Patch document:

[
  { "op": "replace", "path": "/baz", "value": "boo" }
]

The resulting JSON document:

{
  "baz": "boo",
  "foo": "bar"
}

A.6. Moving a Value πŸ¦‹

An example target JSON document:

{
  "foo": {
    "bar": "baz",
    "waldo": "fred"
  },
  "qux": {
    "corge": "grault"
  }
}

A JSON Patch document:

[
  { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }
]

The resulting JSON document:

{
  "foo": {
    "bar": "baz"
  },
  "qux": {
    "corge": "grault",
    "thud": "fred"
  }
}

A.7. Moving an Array Element πŸ¦‹

An example target JSON document:

{ "foo": [ "all", "grass", "cows", "eat" ] }

A JSON Patch document:

[
  { "op": "move", "from": "/foo/1", "path": "/foo/3" }
]

The resulting JSON document:

{ "foo": [ "all", "cows", "eat", "grass" ] }

A.8. Testing a Value: Success βœ…

An example target JSON document:

{
  "baz": "qux",
  "foo": [ "a", 2, "c" ]
}

A JSON Patch document that will result in successful evaluation:

[
  { "op": "test", "path": "/baz", "value": "qux" },
  { "op": "test", "path": "/foo/1", "value": 2 }
]

A.9. Testing a Value: Error ❌

An example target JSON document:

{ "baz": "qux" }

A JSON Patch document that will result in an error condition:

[
  { "op": "test", "path": "/baz", "value": "bar" }
]

A.10. Adding a Nested Member Object 🧁

An example target JSON document:

{ "foo": "bar" }

A JSON Patch document:

[
  { "op": "add", "path": "/child", "value": { "grandchild": { } } }
]

The resulting JSON document:

{
  "foo": "bar",
  "child": {
    "grandchild": {
    }
  }
}

A.11. Ignoring Unrecognized Elements πŸ™ˆ

An example target JSON document:

{ "foo": "bar" }

A JSON Patch document:

[
  { "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }
]

The resulting JSON document:

{
  "foo": "bar",
  "baz": "qux"
}

A.12. Adding to a Nonexistent Target 🫠

An example target JSON document:

{ "foo": "bar" }

A JSON Patch document:

[
  { "op": "add", "path": "/baz/bat", "value": "qux" }
]

This JSON Patch document, applied to the target JSON document above, would result in an error (therefore, it would not be applied), because the "add" operation's target location that references neither the root of the document, nor a member of an existing object, nor a member of an existing array.

A.13. Invalid JSON Patch Document πŸ’€

A JSON Patch document:

[
  { "op": "add", "path": "/baz", "value": "qux", "op": "remove" }
]

This JSON Patch document cannot be treated as an "add" operation, because it contains a later "op":"remove" element. JSON requires that object member names be unique with a "SHOULD" requirement, and there is no standard error handling for duplicates.

A.14. ~ Escape Ordering 🧩

An example target JSON document:

{
  "/": 9,
  "~1": 10
}

A JSON Patch document:

[
  {"op": "test", "path": "/~01", "value": 10}
]

The resulting JSON document:

{
  "/": 9,
  "~1": 10
}

A.15. Comparing Strings and Numbers βš–οΈ

An example target JSON document:

{
  "/": 9,
  "~1": 10
}

A JSON Patch document:

[
  {"op": "test", "path": "/~01", "value": "10"}
]

This results in an error, because the test fails. The document value is numeric, whereas the value being tested for is a string.

A.16. Adding an Array Value πŸ“

An example target JSON document:

{ "foo": ["bar"] }

A JSON Patch document:

[
  { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }
]

The resulting JSON document:

{ "foo": ["bar", ["abc", "def"]] }

Authors' Addresses πŸ’Œ

Paul C. Bryan (editor)
Salesforce.com

Phone: +1 604 783 1481
EMail: pbryan@anode.ca


Mark Nottingham (editor)
Akamai

EMail: mnot@mnot.net
πŸ“¦ where this page comes from