A leaner and meaner implementation of JSON-Patch. Small footprint. High performance.
With JSON-Patch, you can:
- apply patches
- validate a sequence of patches
- observe for changes (and generate patches when a change is detected)
- compare two objects (to obtain the difference)
JSON-Patch (RFC6902) is a standard format that allows you to update a JSON document by sending the changes rather than the whole document. JSON Patch plays well with the HTTP PATCH verb (method) and REST style programming.
Mark Nottingham has a nice blog about it.
1.22 KB minified and gzipped (3 KB minified)
Tested on 22.10.2015. Compared libraries:
- Starcounter-Jack/JSON-Patch 0.5.4
- bruth/jsonpatch-js 0.5.0
- dharmafly/jsonpatch.js master branch
- jiff 0.7.2 browserified
- json8-patch 0.3.2 browserified
We aim the tests to be fair. Our library puts performance as the #1 priority, while other libraries can have different priorities. If you'd like to update the benchmarks or add a library, please edit the jsperf benchmarks linked above and open an issue to include new results.
- Allows you to apply patches on object trees for incoming traffic.
- Allows you to freely manipulate object trees and then generate patches for outgoing traffic.
- Tested in IE 8-11, Firefox, Chrome, Safari and Node.js
Install the current version (and save it as a dependency):
$ npm install fast-json-patch --save
$ bower install fast-json-patch --save
Include json-patch.js
if you want support for applying patches or
include json-patch-duplex.js
if you also want to generate patches.
Call require to get the instance:
var jsonpatch = require('fast-json-patch')
Applying patches:
var myobj = { firstName:"Albert", contactDetails: { phoneNumbers: [ ] } };
var patches = [
{op:"replace", path:"/firstName", value:"Joachim" },
{op:"add", path:"/lastName", value:"Wester" },
{op:"add", path:"/contactDetails/phoneNumbers/0", value:{ number:"555-123" } }
];
jsonpatch.apply( myobj, patches );
// myobj == { firstName:"Joachim", lastName:"Wester", contactDetails:{ phoneNumbers[ {number:"555-123"} ] } };
Generating patches:
var myobj = { firstName:"Joachim", lastName:"Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
var observer = jsonpatch.observe( myobj );
myobj.firstName = "Albert";
myobj.contactDetails.phoneNumbers[0].number = "123";
myobj.contactDetails.phoneNumbers.push({number:"456"});
var patches = jsonpatch.generate(observer);
// patches == [
// { op:"replace", path="/firstName", value:"Albert"},
// { op:"replace", path="/contactDetails/phoneNumbers/0/number", value:"123"},
// { op:"add", path="/contactDetails/phoneNumbers/1", value:{number:"456"}}];
Comparing two object trees:
var objA = {user: {firstName: "Albert", lastName: "Einstein"}};
var objB = {user: {firstName: "Albert", lastName: "Collins"}};
var diff = jsonpatch.compare(objA, objB));
//diff == [{op: "replace", path: "/user/lastName", value: "Collins"}]
Validating a sequence of patches:
var obj = {user: {firstName: "Albert"}};
var patches = [{op: "replace", path: "/user/firstName", value: "Albert"}, {op: "replace", path: "/user/lastName", value: "Einstein"}];
var errors = jsonpatch.validate(patches, obj);
if (errors.length == 0) {
//there are no errors!
}
else {
for (var i=0; i < errors.length; i++) {
if (!errors[i]) {
console.log("Valid patch at index", i, patches[i]);
}
else {
console.error("Invalid patch at index", i, errors[i], patches[i]);
}
}
}
Available in json-patch.js and json-patch-duplex.js
Applies patches
array on obj
.
If the validate
parameter is set to true
, the patch is extensively validated before applying.
An invalid patch results in throwing an error (see jsonpatch.validate
for more information about the error object).
Returns an array of results - one item for each item in patches
. The type of each item depends on type of operation applied
test
- boolean result of the testremove
,replace
andmove
- original object that has been removedadd
(only when adding to an array) - index at which item has been inserted (useful when using-
alias)
Available in json-patch-duplex.js
Sets up an deep observer on obj
that listens for changes in object tree. When changes are detected, the optional
callback is called with the generated patches array as the parameter.
Returns observer
.
Available in json-patch-duplex.js
If there are pending changes in obj
, returns them synchronously. If a callback
was defined in observe
method, it will be triggered synchronously as well.
If there are no pending changes in obj
, returns an empty array (length 0).
Available in json-patch-duplex.js
Destroys the observer set up on obj
.
Any remaining changes are delivered synchronously (as in jsonpatch.generate
). Note: this is different that ES6/7 Object.unobserve
, which delivers remaining changes asynchronously.
Available in json-patch-duplex.js
Compares object trees obj1
and obj2
and returns the difference relative to obj1
as a patches array.
If there are no differences, returns an empty array (length 0).
Available in json-patch.js and json-patch-duplex.js
Validates a sequence of operations. If tree
parameter is provided, the sequence is additionally validated against the object tree.
If there are no errors, returns undefined. If there is an errors, returns a JsonPatchError object with the following properties:
name
String - short error codemessage
String - long human readable error messageindex
Number - index of the operation in the sequenceoperation
Object - reference to the operationtree
Object - reference to the tree
Possible errors:
Error name | Error message |
---|---|
SEQUENCE_NOT_AN_ARRAY | Patch sequence must be an array |
OPERATION_NOT_AN_OBJECT | Operation is not an object |
OPERATION_OP_INVALID | Operation op property is not one of operations defined in RFC-6902 |
OPERATION_PATH_INVALID | Operation path property is not a valid string |
OPERATION_FROM_REQUIRED | Operation from property is not present (applicable in move and copy operations) |
OPERATION_VALUE_REQUIRED | Operation value property is not present, or undefined (applicable in add , replace and test operations) |
OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED | Operation value property object has at least one undefined value (applicable in add , replace and test operations) |
OPERATION_PATH_CANNOT_ADD | Cannot perform an add operation at the desired path |
OPERATION_PATH_UNRESOLVABLE | Cannot perform the operation at a path that does not exist |
OPERATION_FROM_UNRESOLVABLE | Cannot perform the operation from a path that does not exist |
OPERATION_PATH_ILLEGAL_ARRAY_INDEX | Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index |
OPERATION_VALUE_OUT_OF_BOUNDS | The specified index MUST NOT be greater than the number of elements in the array |
As undefined
type does not exist in JSON, it's also not a valid value of JSON Patch operation. Therefore jsonpatch
will not generate JSON Patches that sets anything to undefined
.
Whenever a value is set to undefined
in JS, JSON-Patch methods generate
and compare
will treat it similarly to how JavaScript method JSON.stringify
(MDN) treats them:
If
undefined
(...) is encountered during conversion it is either omitted (when it is found in an object) or censored tonull
(when it is found in an array).
See the ECMAScript spec for details.
To see the list of recent changes, see Releases.
MIT