jsonpatch

package module
v0.7.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 4, 2026 License: MIT Imports: 11 Imported by: 0

README

JSON Patch Go

Go Reference Go Report Card

A Go library for RFC 6902 JSON Patch plus predicate and extended operations with type-preserving APIs

json-joy compatible: this package follows the JSON Patch, predicate, and extended-operation behavior used by streamich/json-joy.

Features

  • Type-preserving results: ApplyPatch, ApplyOp, and ApplyOps preserve the input document shape whenever the result can be converted back safely.
  • Broad operation support: Use RFC 6902 operations, predicate operations, and extended operations in one package.
  • Multiple document shapes: Patch map[string]any, structs, []byte, JSON strings, plain strings, primitives, and []any.
  • Executable operations: Build operations with the op package when you want typed operation values instead of JSON-shaped payloads.
  • Codec support: Encode and decode operations through codec/json, codec/compact, and codec/binary.
  • Predictable defaults: Patch application is immutable unless you pass jsonpatch.WithMutate(true).

Installation

go get github.com/kaptinlin/jsonpatch

Quick Start

package main

import (
    "fmt"
    "log"

    "github.com/kaptinlin/jsonpatch"
)

func main() {
    doc := map[string]any{
        "name": "John",
        "tags": []any{"golang"},
    }

    patch := []jsonpatch.Operation{
        {Op: "test", Path: "/name", Value: "John"},
        {Op: "replace", Path: "/name", Value: "Jane"},
        {Op: "add", Path: "/email", Value: "jane@example.com"},
    }

    result, err := jsonpatch.ApplyPatch(doc, patch)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(result.Doc["name"])
    fmt.Println(result.Doc["email"])
    fmt.Println(doc["name"])
}

API Overview

API Use when
ApplyPatch You already have JSON-shaped []Operation values.
ApplyOp You want to execute one compiled operation from op/.
ApplyOps You want to execute compiled operations directly.
ValidateOperation / ValidateOperations You want to validate JSON-shaped operation payloads before applying them.

Executable Operations

Use op/ when you want operation values with methods such as Validate, ToJSON, and ToCompact.

package main

import (
    "fmt"
    "log"

    "github.com/kaptinlin/jsonpatch"
    "github.com/kaptinlin/jsonpatch/op"
)

type User struct {
    Name   string   `json:"name"`
    Active bool     `json:"active"`
    Roles  []string `json:"roles"`
}

func main() {
    user := User{Name: "John", Active: true, Roles: []string{"admin"}}

    ops := []jsonpatch.Op{
        op.NewTest([]string{"active"}, true),
        op.NewReplace([]string{"name"}, "Jane"),
        op.NewAdd([]string{"roles", "-"}, "owner"),
    }

    result, err := jsonpatch.ApplyOps(user, ops)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(result.Doc.Name)
    fmt.Println(result.Doc.Roles)
}

Document Shapes

Input Processing model Output
map[string]any Apply directly map[string]any
[]byte Decode JSON, apply, encode JSON []byte
string starting with { or [ Decode JSON, apply, encode JSON string
Other string Treat as a plain string value string
Structs and concrete types Marshal to JSON, apply, unmarshal back Original Go type
Primitives and []any Apply directly when assignable Original Go type

Codecs

Compact Codec

Use codec/compact when you want the array-based wire format.

ops := []jsonpatch.Op{
    op.NewAdd([]string{"name"}, "Jane"),
    op.NewInc([]string{"version"}, 1),
}

encoded, err := compact.EncodeJSON(ops)
if err != nil {
    log.Fatal(err)
}

decoded, err := compact.DecodeJSON(encoded)
if err != nil {
    log.Fatal(err)
}

fmt.Println(len(decoded))
Binary Codec

Use codec/binary when you want MessagePack encoding for executable operations. Second-order predicates (and, or, not) are not supported by the binary codec.

codec := binary.New()

data, err := codec.Encode(ops)
if err != nil {
    log.Fatal(err)
}

decoded, err := codec.Decode(data)
if err != nil {
    log.Fatal(err)
}

fmt.Println(len(decoded))

Examples

Explore the runnable examples in examples/:

Development

task test
task lint

For development guidelines, see AGENTS.md. For technical contracts, see SPECS/.

Contributing

See CONTRIBUTING.md.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Overview

Package jsonpatch applies JSON Patch, predicate, and extended operations to Go values.

It implements RFC 6902 JSON Patch together with the predicate and extended operations used by json-joy while preserving the input document type across ApplyPatch, ApplyOp, and ApplyOps.

See https://www.rfc-editor.org/rfc/rfc6902 See https://www.ietf.org/archive/id/draft-snell-json-test-01.txt

Example
package main

import (
	"fmt"

	"github.com/go-json-experiment/json"
	"github.com/go-json-experiment/json/jsontext"

	"github.com/kaptinlin/jsonpatch"
)

func main() {
	// Original document
	doc := map[string]any{
		"user": map[string]any{
			"name":  "Alice",
			"email": "alice@example.com",
			"age":   25,
		},
		"settings": map[string]any{
			"theme": "dark",
		},
	}

	// Create patch operations
	patch := []jsonpatch.Operation{
		// Add a new field
		{
			Op:    "add",
			Path:  "/user/active",
			Value: true,
		},
		// Update existing field
		{
			Op:    "replace",
			Path:  "/user/age",
			Value: 26,
		},
		// Add to settings
		{
			Op:    "add",
			Path:  "/settings/notifications",
			Value: true,
		},
	}

	// Apply patch
	result, err := jsonpatch.ApplyPatch(doc, patch)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}

	// Print result
	resultJSON, _ := json.Marshal(result.Doc, jsontext.Multiline(true), json.Deterministic(true))
	fmt.Println(string(resultJSON))

}
Output:
{
	"settings": {
		"notifications": true,
		"theme": "dark"
	},
	"user": {
		"active": true,
		"age": 26,
		"email": "alice@example.com",
		"name": "Alice"
	}
}

Index

Examples

Constants

View Source
const (
	// JSON Patch (RFC 6902) operations
	OpAddType     = internal.OpAddType
	OpRemoveType  = internal.OpRemoveType
	OpReplaceType = internal.OpReplaceType
	OpMoveType    = internal.OpMoveType
	OpCopyType    = internal.OpCopyType
	OpTestType    = internal.OpTestType

	// JSON Predicate operations
	OpContainsType      = internal.OpContainsType
	OpDefinedType       = internal.OpDefinedType
	OpUndefinedType     = internal.OpUndefinedType
	OpTypeType          = internal.OpTypeType
	OpTestTypeType      = internal.OpTestTypeType
	OpTestStringType    = internal.OpTestStringType
	OpTestStringLenType = internal.OpTestStringLenType
	OpEndsType          = internal.OpEndsType
	OpStartsType        = internal.OpStartsType
	OpInType            = internal.OpInType
	OpLessType          = internal.OpLessType
	OpMoreType          = internal.OpMoreType
	OpMatchesType       = internal.OpMatchesType

	// Composite operations
	OpAndType = internal.OpAndType
	OpOrType  = internal.OpOrType
	OpNotType = internal.OpNotType

	// Extended operations
	OpFlipType   = internal.OpFlipType
	OpIncType    = internal.OpIncType
	OpStrInsType = internal.OpStrInsType
	OpStrDelType = internal.OpStrDelType
	OpSplitType  = internal.OpSplitType
	OpMergeType  = internal.OpMergeType
	OpExtendType = internal.OpExtendType
)

These constants name the supported operations.

View Source
const (
	// JSON Patch (RFC 6902) operations
	OpAddCode     = internal.OpAddCode
	OpRemoveCode  = internal.OpRemoveCode
	OpReplaceCode = internal.OpReplaceCode
	OpCopyCode    = internal.OpCopyCode
	OpMoveCode    = internal.OpMoveCode
	OpTestCode    = internal.OpTestCode

	// String editing
	OpStrInsCode = internal.OpStrInsCode
	OpStrDelCode = internal.OpStrDelCode

	// Extra
	OpFlipCode = internal.OpFlipCode
	OpIncCode  = internal.OpIncCode

	// Slate.js
	OpSplitCode  = internal.OpSplitCode
	OpMergeCode  = internal.OpMergeCode
	OpExtendCode = internal.OpExtendCode

	// JSON Predicate
	OpContainsCode      = internal.OpContainsCode
	OpDefinedCode       = internal.OpDefinedCode
	OpEndsCode          = internal.OpEndsCode
	OpInCode            = internal.OpInCode
	OpLessCode          = internal.OpLessCode
	OpMatchesCode       = internal.OpMatchesCode
	OpMoreCode          = internal.OpMoreCode
	OpStartsCode        = internal.OpStartsCode
	OpUndefinedCode     = internal.OpUndefinedCode
	OpTestTypeCode      = internal.OpTestTypeCode
	OpTestStringCode    = internal.OpTestStringCode
	OpTestStringLenCode = internal.OpTestStringLenCode
	OpTypeCode          = internal.OpTypeCode
	OpAndCode           = internal.OpAndCode
	OpNotCode           = internal.OpNotCode
	OpOrCode            = internal.OpOrCode
)

Operation code constants (numeric constants)

View Source
const JSONPatchTypeArray = internal.JSONPatchTypeArray

JSONPatchTypeArray represents the JSON array type.

View Source
const JSONPatchTypeBoolean = internal.JSONPatchTypeBoolean

JSONPatchTypeBoolean represents the JSON boolean type.

View Source
const JSONPatchTypeInteger = internal.JSONPatchTypeInteger

JSONPatchTypeInteger represents the JSON integer type.

View Source
const JSONPatchTypeNull = internal.JSONPatchTypeNull

JSONPatchTypeNull represents the JSON null type.

View Source
const JSONPatchTypeNumber = internal.JSONPatchTypeNumber

JSONPatchTypeNumber represents the JSON number type.

View Source
const JSONPatchTypeObject = internal.JSONPatchTypeObject

JSONPatchTypeObject represents the JSON object type.

View Source
const JSONPatchTypeString = internal.JSONPatchTypeString

JSONPatchTypeString represents the JSON string type.

Variables

View Source
var (
	IsValidJSONPatchType = internal.IsValidJSONPatchType
	GetJSONPatchType     = internal.GetJSONPatchType

	// Operation type checking functions
	IsJSONPatchOperation            = internal.IsJSONPatchOperation
	IsPredicateOperation            = internal.IsPredicateOperation
	IsFirstOrderPredicateOperation  = internal.IsFirstOrderPredicateOperation
	IsSecondOrderPredicateOperation = internal.IsSecondOrderPredicateOperation
	IsJSONPatchExtendedOperation    = internal.IsJSONPatchExtendedOperation
)

Re-export functions

View Source
var (
	// ErrNoOperationDecoded reports that decoding produced no operations.
	ErrNoOperationDecoded = errors.New("no operation decoded")
	// ErrInvalidDocumentType reports that the input document cannot be handled.
	ErrInvalidDocumentType = errors.New("invalid document type")
	// ErrConversionFailed reports that a patched result could not be converted back.
	ErrConversionFailed = errors.New("failed to convert result back to original type")
	// ErrNoOperationResult reports that ApplyOp received no per-operation result.
	ErrNoOperationResult = errors.New("no operation result")
)
View Source
var (
	// ErrNotArray reports that a patch value is not an operation array.
	ErrNotArray = errors.New("not an array")
	// ErrEmptyPatch reports that no operations were provided.
	ErrEmptyPatch = errors.New("empty operation patch")
	// ErrInvalidOperation reports that an operation name is unknown.
	ErrInvalidOperation = errors.New("invalid operation")
	// ErrMissingPath reports that an operation is missing its path field.
	ErrMissingPath = errors.New("missing required field 'path'")
	// ErrMissingOp reports that an operation is missing its op field.
	ErrMissingOp = errors.New("missing required field 'op'")
	// ErrMissingValue reports that an operation is missing its value field.
	ErrMissingValue = errors.New("missing required field 'value'")
	// ErrMissingFrom reports that an operation is missing its from field.
	ErrMissingFrom = errors.New("missing required field 'from'")
	// ErrInvalidPath reports that path has the wrong JSON type.
	ErrInvalidPath = errors.New("field 'path' must be a string")
	// ErrInvalidOp reports that op has the wrong JSON type.
	ErrInvalidOp = errors.New("field 'op' must be a string")
	// ErrInvalidFrom reports that from has the wrong JSON type.
	ErrInvalidFrom = errors.New("field 'from' must be a string")
	// ErrInvalidJSONPointer reports that a path or from value is not a valid JSON Pointer.
	ErrInvalidJSONPointer = errors.New("invalid JSON pointer")
	// ErrInvalidOldValue reports that oldValue has an invalid shape.
	ErrInvalidOldValue = errors.New("invalid oldValue")
	// ErrCannotMoveToChildren reports that a move target is nested under its source.
	ErrCannotMoveToChildren = errors.New("cannot move into own children")
	// ErrInvalidIncValue reports that an inc operand has an invalid type.
	ErrInvalidIncValue = errors.New("invalid inc value")
	// ErrExpectedStringField reports that a field must contain a string.
	ErrExpectedStringField = errors.New("expected string field")
	// ErrExpectedBooleanField reports that a field must contain a boolean.
	ErrExpectedBooleanField = errors.New("expected field to be boolean")
	// ErrExpectedIntegerField reports that a field must contain an integer.
	ErrExpectedIntegerField = errors.New("not an integer")
	// ErrNegativeNumber reports that a numeric field is negative.
	ErrNegativeNumber = errors.New("number is negative")
	// ErrInvalidProps reports that props has an invalid shape.
	ErrInvalidProps = errors.New("invalid props field")
	// ErrInvalidTypeField reports that type has an invalid shape.
	ErrInvalidTypeField = errors.New("invalid type field")
	// ErrEmptyTypeList reports that a type list is empty.
	ErrEmptyTypeList = errors.New("empty type list")
	// ErrInvalidType reports that a JSON type name is unsupported.
	ErrInvalidType = errors.New("invalid type")
	// ErrValueMustBeString reports that value must be a string.
	ErrValueMustBeString = errors.New("value must be a string")
	// ErrValueMustBeNumber reports that value must be numeric.
	ErrValueMustBeNumber = errors.New("value must be a number")
	// ErrValueMustBeArray reports that value must be an array.
	ErrValueMustBeArray = errors.New("value must be an array")
	// ErrValueTooLong reports that a provided value exceeds the allowed length.
	ErrValueTooLong = errors.New("value too long")
	// ErrInvalidNotModifier reports that not was supplied where it is unsupported.
	ErrInvalidNotModifier = errors.New("invalid not modifier")
	// ErrMatchesNotAllowed reports that matches is disabled for this validation pass.
	ErrMatchesNotAllowed = errors.New("matches operation not allowed")
	// ErrMustBeArray reports that a value must decode to an array.
	ErrMustBeArray = errors.New("must be an array")
	// ErrEmptyPredicateList reports that a composite predicate has no operands.
	ErrEmptyPredicateList = errors.New("predicate list is empty")
	// ErrPosGreaterThanZero reports that pos must be greater than zero.
	ErrPosGreaterThanZero = errors.New("expected pos field to be greater than 0")
	// ErrInOperationValueMustBeArray reports that in requires an array value.
	ErrInOperationValueMustBeArray = errors.New("in operation value must be an array")
	// ErrExpectedValueToBeString reports that value must decode as a string.
	ErrExpectedValueToBeString = errors.New("expected value to be string")
	// ErrExpectedIgnoreCaseBoolean reports that ignore_case must decode as a boolean.
	ErrExpectedIgnoreCaseBoolean = errors.New("expected ignore_case to be boolean")
	// ErrExpectedFieldString reports that a field must decode as a string.
	ErrExpectedFieldString = errors.New("expected field to be string")
)
View Source
var WithMatcher = internal.WithMatcher

WithMatcher sets the regex matcher factory used by pattern operations.

View Source
var WithMutate = internal.WithMutate

WithMutate enables or disables in-place mutation.

Functions

func ApplyOp

func ApplyOp[T internal.Document](doc T, op internal.Op, opts ...internal.Option) (*internal.OpResult[T], error)

ApplyOp applies a single operation to a document with generic type support. It automatically detects the document type and applies the appropriate strategy. Returns an OpResult containing the patched document and old value.

Example usage:

// Struct
user := User{Name: "John", Age: 30}
result, err := ApplyOp(user, op, WithMutate(false))
if err == nil {
	patchedUser := result.Doc // Type: User
	oldValue := result.Old    // Previous value
}

// Map
doc := map[string]any{"name": "John", "age": 30}
result, err := ApplyOp(doc, op, WithMutate(true))

The function preserves the input type: struct input returns struct output, map input returns map output, etc.

func ApplyOps

func ApplyOps[T internal.Document](doc T, ops []internal.Op, opts ...internal.Option) (*internal.PatchResult[T], error)

ApplyOps applies multiple operations to a document with generic type support. Applies Op instances directly without JSON serialization roundtrip. Returns a PatchResult containing the patched document and operation results.

Example usage:

// Struct
user := User{Name: "John", Age: 30}
result, err := ApplyOps(user, ops, WithMutate(false))
if err == nil {
	patchedUser := result.Doc // Type: User
	opResults := result.Res   // Operation results
}

// Map
doc := map[string]any{"name": "John", "age": 30}
result, err := ApplyOps(doc, ops, WithMutate(true))

The function preserves the input type: struct input returns struct output, map input returns map output, etc.

func ApplyPatch

func ApplyPatch[T internal.Document](doc T, patch []internal.Operation, opts ...internal.Option) (*internal.PatchResult[T], error)

ApplyPatch applies patch to doc and returns the patched document with per-operation results.

ApplyPatch preserves the input document type. String inputs are parsed as JSON only when they begin with '{' or '['. Unless WithMutate(true) is set, ApplyPatch works on a clone.

func DefaultOptions added in v0.2.0

func DefaultOptions() *internal.Options

DefaultOptions returns the default patch options.

func ValidateOperation

func ValidateOperation(op Operation, allowMatchesOp bool) error

ValidateOperation validates a single JSON Patch operation.

func ValidateOperations

func ValidateOperations(ops []Operation, allowMatchesOp bool) error

ValidateOperations validates an array of JSON Patch operations.

Types

type CreateRegexMatcher

type CreateRegexMatcher = internal.CreateRegexMatcher

CreateRegexMatcher is a function type that creates a RegexMatcher from a pattern. This aligns with json-joy's CreateRegexMatcher type.

type Document added in v0.2.0

type Document = internal.Document

Document is the set of document types supported by the generic API.

type Op

type Op = internal.Op

Op applies itself to a document.

type OpResult

type OpResult[T Document] = internal.OpResult[T]

OpResult is the result of applying one operation.

type OpType

type OpType = internal.OpType

OpType names a JSON Patch operation.

type Operation

type Operation = internal.Operation

Operation aliases internal.Operation.

type Option added in v0.2.0

type Option = internal.Option

Option applies one patch option.

type Options added in v0.2.0

type Options = internal.Options

Options configures patch application.

type PatchResult

type PatchResult[T Document] = internal.PatchResult[T]

PatchResult is the result of applying a sequence of operations.

type RegexMatcher

type RegexMatcher = internal.RegexMatcher

RegexMatcher is a function type that tests if a value matches a pattern. This aligns with json-joy's RegexMatcher type.

func CreateMatcherDefault

func CreateMatcherDefault(pattern string, ignoreCase bool) RegexMatcher

CreateMatcherDefault creates a regex matcher from a pattern and case sensitivity flag. Returns a matcher that always returns false if pattern compilation fails. This aligns with json-joy's createMatcherDefault behavior.

type Types added in v0.4.3

type Types = internal.JSONPatchType

Types represents the valid JSON types for type operations.

Directories

Path Synopsis
codec
binary
Package binary implements a MessagePack-based binary codec for JSON Patch operations.
Package binary implements a MessagePack-based binary codec for JSON Patch operations.
compact
Package compact implements an array-based codec for JSON Patch operations.
Package compact implements an array-based codec for JSON Patch operations.
json
Package json implements a codec for JSON Patch operations with full RFC 6902, JSON Predicate, and extended operation support.
Package json implements a codec for JSON Patch operations with full RFC 6902, JSON Predicate, and extended operation support.
json/tests
Package tests provides test data and automated codec tests for the JSON codec.
Package tests provides test data and automated codec tests for the JSON codec.
examples
array-operations command
Package main demonstrates array operations using JSON Patch.
Package main demonstrates array operations using JSON Patch.
basic command
Package main demonstrates basic JSON Patch operations.
Package main demonstrates basic JSON Patch operations.
basic-operations command
Package main demonstrates basic JSON Patch operations.
Package main demonstrates basic JSON Patch operations.
batch-update command
Package main demonstrates batch update operations using JSON Patch.
Package main demonstrates batch update operations using JSON Patch.
binary-codec command
Package main demonstrates binary codec operations using JSON Patch.
Package main demonstrates binary codec operations using JSON Patch.
compact-codec command
Package main demonstrates the compact codec functionality.
Package main demonstrates the compact codec functionality.
conditional-operations command
Package main demonstrates conditional operations using JSON Patch.
Package main demonstrates conditional operations using JSON Patch.
copy-move-operations command
Package main demonstrates copy and move operations using JSON Patch.
Package main demonstrates copy and move operations using JSON Patch.
error-handling command
Package main demonstrates error handling with JSON Patch operations.
Package main demonstrates error handling with JSON Patch operations.
errors command
Package main demonstrates error handling in JSON Patch operations.
Package main demonstrates error handling in JSON Patch operations.
extended command
Package main demonstrates extended JSON Patch operations.
Package main demonstrates extended JSON Patch operations.
json-bytes-patch command
Package main demonstrates JSON bytes patching operations.
Package main demonstrates JSON bytes patching operations.
json-string-patch command
Package main demonstrates JSON string patching operations.
Package main demonstrates JSON string patching operations.
map-patch command
Package main demonstrates map patching operations using JSON Patch.
Package main demonstrates map patching operations using JSON Patch.
mutate-option command
Package main demonstrates mutate option usage with JSON Patch.
Package main demonstrates mutate option usage with JSON Patch.
string-operations command
Package main demonstrates string operations using JSON Patch.
Package main demonstrates string operations using JSON Patch.
struct-patch command
Package main demonstrates struct patching operations using JSON Patch.
Package main demonstrates struct patching operations using JSON Patch.
types command
Package main demonstrates type operations with JSON Patch.
Package main demonstrates type operations with JSON Patch.
Package internal provides shared types, interfaces, and constants for JSON Patch operations.
Package internal provides shared types, interfaces, and constants for JSON Patch operations.
Package op provides implementations for JSON Patch operations.
Package op provides implementations for JSON Patch operations.
tests
data
Package data contains test case data and specifications for JSON Patch operations.
Package data contains test case data and specifications for JSON Patch operations.
testutils
Package testutils provides shared utilities for JSON Patch testing.
Package testutils provides shared utilities for JSON Patch testing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL