Files
json/api/basic_json/patch/index.md
T
2026-10-26 21:24:35 +00:00

8.4 KiB

nlohmann::basic_json::patch

basic_json patch(const basic_json& json_patch) const;

JSON Patch defines a JSON document structure for expressing a sequence of operations to apply to a JSON document. With this function, a JSON Patch is applied to the current JSON value by executing all operations from the patch.

Parameters

json_patch (in) : JSON patch document

Return value

patched document

Exception safety

Strong guarantee: if an exception is thrown, there are no changes in the JSON value.

Exceptions

  • Throws parse_error.104 if the JSON patch does not consist of an array of objects.
  • Throws parse_error.105 if the JSON patch is malformed (e.g., mandatory attributes are missing); example: "operation 'add' must have member 'path'".
  • Throws out_of_range.401 if an array index is out of range.
  • Throws parse_error.106 if an array index in a "path" or "from" member begins with '0'; example: "array index '01' must not begin with '0'".
  • Throws parse_error.107 if a "path" or "from" member is not empty and does not begin with a slash (/); example: "JSON pointer must be empty or begin with '/' - was: 'a'".
  • Throws parse_error.108 if a tilde (~) in a "path" or "from" member is not followed by 0 or 1; example: "escape character '~' must be followed with '0' or '1'".
  • Throws parse_error.109 if an array index in a "path" or "from" member is not a number; example: "array index 'foo' is not a number".
  • Throws out_of_range.402 if the array index - is used where an existing element is required (the "path" of "replace", the "from" of "move" and "copy"); example: "array index '-' (3) is out of range".
  • Throws out_of_range.403 if a JSON pointer inside the patch could not be resolved successfully in the current JSON value; example: "key 'baz' not found".
  • Throws out_of_range.404 if a reference token of a JSON pointer inside the patch cannot be resolved, e.g., - in a "remove" operation or 1a for an array; example: "unresolved reference token '-'".
  • Throws out_of_range.405 if JSON pointer has no parent ("remove", "move")
  • Throws out_of_range.411 if an "add" operation's target location has a parent that is neither an object nor an array.
  • Throws out_of_range.413 if a "remove" operation's target location has a parent that is neither an object nor an array.
  • Throws out_of_range.414 if a "move" operation's "from" location is a proper prefix of its "path" location.
  • Throws other_error.501 if "test" operation was unsuccessful. A "test" operation whose "path" does not exist is unsuccessful, too: the failed lookup is reported as a failed test, even if the operation has no "value" member (which would otherwise be parse_error.105). Which of the two errors is reported for this combination depends on the order in which the operands of a comparison are evaluated, so do not rely on it.

Complexity

Linear in the size of the JSON value and the length of the JSON patch. As usually the patch affects only a fraction of the JSON value, the complexity can usually be neglected.

Notes

The application of a patch is atomic: Either all operations succeed and the patched document is returned or an exception is thrown. In any case, the original value is not changed: the patch is applied to a copy of the value.

Duplicate member names inside an operation object are resolved by the parser before the patch is applied (the last one is kept, see object_t), so {"op": "add", "op": "remove", "path": "/a"} is a remove operation.

Examples

Example: apply a JSON patch

The following code shows how a JSON patch is applied to a value.

#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>

using nlohmann::json;
using namespace nlohmann::literals;

int main()
{
    // the original document
    json doc = R"(
        {
          "baz": "qux",
          "foo": "bar"
        }
    )"_json;

    // the patch
    json patch = R"(
        [
          { "op": "replace", "path": "/baz", "value": "boo" },
          { "op": "add", "path": "/hello", "value": ["world"] },
          { "op": "remove", "path": "/foo"}
        ]
    )"_json;

    // apply the patch
    json patched_doc = doc.patch(patch);

    // output original and patched document
    std::cout << std::setw(4) << doc << "\n\n"
              << std::setw(4) << patched_doc << '\n';
}

Output:

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

{
    "baz": "boo",
    "hello": [
        "world"
    ]
}

Example: out_of_range.414 exception

The following code shows how a "move" operation whose "from" location is a proper prefix of its "path" location is rejected, and how the original document is left unchanged because the patch is applied to a copy.

#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>

using nlohmann::json;
using namespace nlohmann::literals;

int main()
{
    // the original document
    json doc = R"(
        {
          "a": { "b": 1 }
        }
    )"_json;

    // a patch that tries to move "/a" into one of its own children
    json patch = R"(
        [
          { "op": "move", "from": "/a", "path": "/a/b" }
        ]
    )"_json;

    // exception out_of_range.414
    try
    {
        json patched_doc = doc.patch(patch);
    }
    catch (const json::out_of_range& e)
    {
        std::cout << e.what() << '\n';
    }

    // the original document is unchanged
    std::cout << std::setw(4) << doc << '\n';
}

Output:

[json.exception.out_of_range.414] cannot move value: 'from' path '/a' is a proper prefix of 'path' '/a/b'
{
    "a": {
        "b": 1
    }
}

See also

Version history

  • Added in version 2.0.0.
  • Added out_of_range.411 and stopped relying on an internal assertion when an "add" operation's target location has a non-object/non-array parent in version 3.13.0 unreleased. This includes a null parent, which was previously silently converted to an object, in version 3.13.0 unreleased.
  • Added out_of_range.413 and stopped silently ignoring a "remove" operation whose target location has a non-object/non-array parent in version 3.13.0 unreleased.
  • Added out_of_range.414 and rejected a "move" operation whose "from" location is a proper prefix of its "path" location instead of silently producing a corrupted result in version 3.13.0 unreleased.
  • Throws parse_error.109 instead of out_of_range.404 for a one-character array index that is not a digit (e.g., /x) in version 3.13.0 unreleased, as it already did for longer ones.