Fundamentals 11 min read

Mastering JSON Patch: Efficiently Modify JSON with RFC 6902

This article explains the JSON Patch standard (RFC 6902), detailing its purpose, structure, supported operations, ordering and atomicity rules, and provides concrete code examples for add, remove, replace, move, copy, and test operations, including edge‑case handling.

System Architect Go
System Architect Go
System Architect Go
Mastering JSON Patch: Efficiently Modify JSON with RFC 6902

Introduction

JSON Patch is defined by RFC 6902 and is used with the HTTP PATCH method. The MIME type for a JSON Patch document is application/json-patch+json.

Patch Document Structure

A JSON Patch is a JSON array where each element is an operation object. Every operation object must contain an op member that specifies the operation type. Depending on the operation, additional members such as path, value, or from are required.

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

Operations are applied sequentially in the order they appear. The patch is atomic: either all operations succeed and the target document is modified, or none are applied.

The order of keys inside an operation object does not matter.

Patch objects are executed in array order.

Each operation is atomic; a failure aborts the entire patch.

Supported Operations

add
remove
replace
move
copy
test

add

The add operation inserts a value at the location identified by path. The behavior depends on the target:

If path points to an array index, the value is inserted at that position, shifting subsequent elements.

If path points to a non‑existent object member, the member is created.

If path points to an existing member, the member's value is replaced.

Examples:

Add an object member:

# source data:
{ "foo": "bar" }
# JSON Patch:
[ { "op": "add", "path": "/baz", "value": "qux" } ]
# result:
{ "baz": "qux", "foo": "bar" }

Add an array element at index 1:

# source data:
{ "foo": ["bar", "baz"] }
# JSON Patch:
[ { "op": "add", "path": "/foo/1", "value": "qux" } ]
# result:
{ "foo": ["bar", "qux", "baz"] }

Add a nested object:

# source data:
{ "foo": "bar" }
# JSON Patch:
[ { "op": "add", "path": "/child", "value": { "grandchild": {} } } ]
# result:
{ "foo": "bar", "child": { "grandchild": {} } }

remove

The remove operation deletes the value at path. When the target is an array index, the array is compacted by shifting elements left.

Examples:

Remove an object member:

# source data:
{ "baz": "qux", "foo": "bar" }
# JSON Patch:
[ { "op": "remove", "path": "/baz" } ]
# result:
{ "foo": "bar" }

Remove an array element:

# source data:
{ "foo": ["bar", "qux", "baz"] }
# JSON Patch:
[ { "op": "remove", "path": "/foo/1" } ]
# result:
{ "foo": ["bar", "baz"] }

replace

The replace operation substitutes the value at path with value. It is equivalent to a remove followed by an add on the same path.

# source data:
{ "baz": "qux", "foo": "bar" }
# JSON Patch:
[ { "op": "replace", "path": "/baz", "value": "boo" } ]
# result:
{ "baz": "boo", "foo": "bar" }

move

The move operation transfers a value from from to path. The from location must not be a parent of path (i.e., you cannot move a value into one of its own descendants).

# source data:
{ "foo": { "waldo": "fred" }, "qux": {} }
# JSON Patch:
[ { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" } ]
# result:
{ "foo": {}, "qux": { "thud": "fred" } }

copy

The copy operation duplicates the value from from to path without removing the source.

test

The test operation verifies that the value at path is equal to value. Equality follows type‑specific rules (strings must match exactly, numbers must be numerically equal, arrays and objects are compared recursively, and booleans/null must be identical). If any test fails, the entire patch is rejected.

# source data:
{ "baz": "qux", "foo": ["a", 2, "c"] }
# JSON Patch (successful):
[ { "op": "test", "path": "/baz", "value": "qux" },
  { "op": "test", "path": "/foo/1", "value": 2 } ]

Escaping Special Characters in Paths

In JSON Pointer syntax, the characters ~ and / must be escaped. ~ becomes ~0 and / becomes ~1.

# source data:
{ "/": 9, "~1": 10 }
# JSON Patch:
[ { "op": "test", "path": "/~01", "value": 10 } ]
# result: document unchanged because the test succeeds.

Conclusion

JSON Patch enables fine‑grained updates to JSON documents without transmitting the entire payload. It is widely adopted in APIs such as Kubernetes and many other RESTful services.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JSONAPIHTTP PATCHJSON PatchRFC 6902
System Architect Go
Written by

System Architect Go

Programming, architecture, application development, message queues, middleware, databases, containerization, big data, image processing, machine learning, AI, personal growth.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.