fast-json-patch

repository·master·Indexed 24 days ago

https://github.com/starcounter-jack/json-patch

A high-performance, small-footprint JavaScript implementation of the JSON-Patch (RFC 6902) standard. It provides capabilities for applying patches via applyPatch and applyOperation, validating patch sequences, comparing two objects to generate differences, and observing object changes to generate patches in real-time.

Tokens
5.5K
Snippets
11
Records
36
Agent score
83%

What's inside fast-json-patch

  1. Overview of fast-json-patch capabilities

    master

    The fast-json-patch library is a high-performance implementation of the JSON-Patch [RFC6902] standard. It allows you to update JSON documents by sending only the changes rather than the entire document, which is ideal for REST-style programming and the HTTP PATCH method.

    Key features include:

    • Applying patches: Apply arrays of patches or single operations to a JavaScript object.
    • Validation: Validate a sequence of patches.
    • Observation and Generation: Observe changes to an object and generate patches when changes are detected.
    • Comparison: Compare two objects to obtain the difference between them.
  2. Generate patches from object changes with observe() and generate()

    master

    You can track changes to a document and generate JSON patches by using an observer.

    1. observe(document, callback?): Sets up a deep observer on the document. When changes are detected, it triggers the optional callback with the generated patches.
    2. generate(observer, invertible = false): Synchronously returns the pending changes as an array of operations.
      • If invertible is true, each change is preceded by a test operation of the value before the change, allowing you to revert the patch later.
    3. unobserve(document, observer): Destroys the observer. Any remaining changes are delivered synchronously.

    Example (Standard Generation):

    var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
    var observer = jsonpatch.observe(document);
    
    document.firstName = "Albert";
    document.contactDetails.phoneNumbers[0].number = "123";
    document.contactDetails.phoneNumbers.push({ number:"456" });
    
    var patch = jsonpatch.generate(observer);
    // patch == [
    //   { op: "replace", path: "/firstName", value: "Albert"},
    //   { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
    //   { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
    // ];
    var document = { firstName: "Joachim", lastName: "Wester", contactDetails: { phoneNumbers: [ { number:"555-123" }] } };
    var observer = jsonpatch.observe(document);
    
    document.firstName = "Albert";
    document.contactDetails.phoneNumbers[0].number = "123";
    document.contactDetails.phoneNumbers.push({ number:"456" });
    
    var patch = jsonpatch.generate(observer);
    // patch  == [
    //   { op: "replace", path: "/firstName", value: "Albert"},
    //   { op: "replace", path: "/contactDetails/phoneNumbers/0/number", value: "123" },
    //   { op: "add", path: "/contactDetails/phoneNumbers/1", value: {number:"456"}}
    // ];
  3. How `undefined` values are handled

    master

    Since undefined is not a valid value in the JSON specification, jsonpatch does not generate patches that set values to undefined.

    When using generate or compare methods, undefined values are treated according to standard JavaScript JSON.stringify behavior:

    • In an object: The key/value pair is omitted.
    • In an array: The value is converted to null.
  4. Add fast-json-patch to a web browser

    master

    To use the library in a web browser, you can either load the bundled distribution script or use ECMAScript modules in supported browsers.

    Using a script tag:

    <script src="dist/fast-json-patch.min.js"></script>

    Using ECMAScript modules:

    <script type="module">
      import * as jsonpatch from 'fast-json-patch/index.mjs';
      import { applyOperation } from 'fast-json-patch/index.mjs';
    </script>
  5. Add fast-json-patch to Node.js or a bundler

    master

    Depending on your environment, you can import fast-json-patch using ECMAScript modules (ESM) or CommonJS.

    Node.js 12+ (with --experimental-modules flag) or ESM-ready environments:

    import * as jsonpatch from 'fast-json-patch/index.mjs';
    import { applyOperation } from 'fast-json-patch/index.mjs';

    Webpack or other bundlers (e.g., Babel):

    import * as jsonpatch from 'fast-json-patch';
    import { applyOperation } from 'fast-json-patch';

    Standard Node.js (CommonJS):

    const { applyOperation } = require('fast-json-patch');
    const applyOperation = require('fast-json-patch').applyOperation;
    const { applyOperation } = require('fast-json-patch');
  6. JSON Patch Operation Types

    master

    The library supports the following operations defined in RFC-6902:

    OperationopDescription
    AddaddAdds a value at the specified path.
    RemoveremoveRemoves the value at the specified path.
    ReplacereplaceReplaces the value at the specified path with a new value.
    MovemoveMoves a value from one location (from) to another (path).
    CopycopyCopies a value from one location (from) to another (path).
    TesttestTests if the value at the path is equal to the provided value. Fails if not equal.
    Get_getInternal/Extended operation to retrieve a value at a path.
  7. Compare two documents with compare()

    master

    Use jsonpatch.compare(document1, document2, invertible) to find the difference between two object trees. It returns a patch array that transforms document1 into document2.

    • document1: The source document.
    • document2: The target document.
    • invertible: If true, each change is preceded by a test operation of the value in document1.

    If there are no differences, it returns an empty array.

    var documentA = {user: {firstName: "Albert", lastName: "Einstein"}};
    var documentB = {user: {firstName: "Albert", lastName: "Collins"}};
    var diff = jsonpatch.compare(documentA, documentB);
    // diff == [{op: "replace", path: "/user/lastName", value: "Collins"}]
  8. Understand the `OperationResult` return type

    master

    The functions applyPatch and applyOperation return an OperationResult object. This object provides the state of the document after the operation and metadata about what was changed or tested.

    An OperationResult has the following structure:

    • newDocument: The new state of the document after the patch/operation is applied.
    • test: If the operation was a test operation, this contains its boolean result.
    • removed: Contains the values that were removed, moved, or replaced during remove, move, or replace operations.
    {
      newDocument: any,
      test?: boolean,
      removed?: any
    }
  9. Apply patches using applyReducer()

    master

    The applyReducer<T>(document, operation, index) function is designed to be used with Array.prototype.reduce. It is the ideal way to apply a patch array by iterating through it.

    Usage Pattern: const updatedDocument = patch.reduce(jsonpatch.applyReducer, document);

    Note: It throws TEST_OPERATION_FAILED if a test operation fails.

  10. Apply a single operation with applyOperation()

    master

    Use applyOperation<T>(document, operation, ...) to apply a single JSON-Patch operation object to a document.

    Parameters:

    • document: The document to patch.
    • operation: The single operation object.
    • validateOperation: Boolean to enable default validation or a custom Validator<T> callback.
    • mutateDocument: Whether to mutate the original document or clone it (default true).
    • banPrototypeModifications: Whether to prevent __proto__ modifications (default true).
    • index: The index of the operation in its original array (useful for error reporting).

    Note: Like applyPatch, this modifies the document and operation by reference. It throws TEST_OPERATION_FAILED if a test operation fails.

    var document = { firstName: "Albert", contactDetails: { phoneNumbers: [] } };
    var operation = { op: "replace", path: "/firstName", value: "Joachim" };
    document = jsonpatch.applyOperation(document, operation).newDocument;
    // document == { firstName: "Joachim", contactDetails: { phoneNumbers: [] }}