Giter Site home page Giter Site logo

jsonpatch's Introduction

jsonpatch

As per http://jsonpatch.com/ JSON Patch is specified in RFC 6902 from the IETF.

JSON Patch allows you to generate JSON that describes changes you want to make to a document, so you don't have to send the whole doc. JSON Patch format is supported by HTTP PATCH method, allowing for standards based partial updates via REST APIs.

go get github.com/mattbaird/jsonpatch

I tried some of the other "jsonpatch" go implementations, but none of them could diff two json documents and generate format like jsonpatch.com specifies. Here's an example of the patch format:

[
  { "op": "replace", "path": "/baz", "value": "boo" },
  { "op": "add", "path": "/hello", "value": ["world"] },
  { "op": "remove", "path": "/foo"}
]

The API is super simple #example

package main

import (
	"fmt"
	"github.com/mattbaird/jsonpatch"
)

var simpleA = `{"a":100, "b":200, "c":"hello"}`
var simpleB = `{"a":100, "b":200, "c":"goodbye"}`

func main() {
	patch, e := jsonpatch.CreatePatch([]byte(simpleA), []byte(simpleB))
	if e != nil {
		fmt.Printf("Error creating JSON patch:%v", e)
		return
	}
	for _, operation := range patch {
		fmt.Printf("%s\n", operation.Json())
	}
}

This code needs more tests, as it's a highly recursive, type-fiddly monster. It's not a lot of code, but it has to deal with a lot of complexity.

jsonpatch's People

Contributors

cwdsuzhou avatar davaddi avatar e-nikolov avatar epelc avatar jpillora avatar mattbaird avatar tmichaud314 avatar yozel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsonpatch's Issues

Empty patch when compare two arrays

Hello,

first thanks for your effort creating this library.

I was wondering if the following behavior is intended?

Actual Behavior

If the following code is executed the result is an empty patch.
The reason for that is that the 2nd item in o2 is the "same" item like the item in o1.

import (
	"fmt"

	"github.com/mattbaird/jsonpatch"
)

func main() {

	o1 := []byte(`{"Items":[{"K":1}]}`)
	o2 := []byte(`{"Items":[{"K":1},{"K":1}]}`)

	patch, err := jsonpatch.CreatePatch(o1, o2)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("Patch", patch)

}

Expected Behavior

I did expect to get the following patch

[{"op": "add", "path": "/Items/1", "value": {"K":1}}]

Specifications

Version: newest (go get github.com/mattbaird/jsonpatch)

Generated patch incorrect for Array replacement

Thanks for this handy library. I am trying to generate JSON patch . Here is a case that produces buggy patch:

src = {
  "spec": {
    "loadBalancerSourceRanges": [
      "192.101.0.0/16",
      "192.0.0.0/24"
    ]
  }
}

dst = {
  "spec": {
    "loadBalancerSourceRanges": [
      "192.101.0.0/24"
    ]
  }
}

The generated patch is:

[
  {
    "op": "remove",
    "path": "/spec/loadBalancerSourceRanges/0"
  },  
  {
    "op": "remove",
    "path": "/spec/loadBalancerSourceRanges/1"
  },
  {
    "op": "add",
    "path": "/spec/loadBalancerSourceRanges/0",
    "value": "192.101.0.0/24"
  }
]

This results in an error. The problem seems to be that index 1 should be removed before index 0. If I reverse the order the generated patch works.

I tested patch generation using https://github.com/stefankoegl/python-json-patch library . This produces a valid patch:

[{"path": "/spec/loadBalancerSourceRanges/1", "op": "remove"}, {"path": "/spec/loadBalancerSourceRanges/0", "value": "192.101.0.0/24", "op": "replace"}]

https://gist.github.com/tamalsaha/e8b313aec8f8d8191bc01ba504247e30

I also tested against a node.js library here: https://json8.github.io/patch/demos/apply/ . I get the same issue.

I wonder if you can fix this or give us pointers on how to fix this.

Improvable patch

Thanks for making this project :) See program and output. It would nice if it instead produced a 2 operation patch: remove 0 and add 10 "..." instead of 10 replaces. (Side question: do removes need to contain the removed value?)

package main

import (
    "encoding/json"
    "log"

    "github.com/mattbaird/jsonpatch"
)

type Log struct {
    Lines []int
}

func main() {

    size := 10

    lines := make([]int, size)
    for i := 0; i < size; i++ {
        lines[i] = i + 1
    }

    a, _ := json.Marshal(&Log{Lines: lines})
    log.Printf("%s", a)

    //remove from the front
    lines = lines[1:]
    //add to the end
    lines = append(lines, size+1)

    b, _ := json.Marshal(&Log{Lines: lines})
    log.Printf("%s", b)

    ops, err := jsonpatch.CreatePatch(a, b)
    if err != nil {
        log.Fatal(err)
    }

    delta, _ := json.MarshalIndent(ops, "", "  ")
    log.Printf("%s", delta)
}
$ go run patch.go
2015/07/11 17:22:28 {"Lines":[1,2,3,4,5,6,7,8,9,10]}
2015/07/11 17:22:28 {"Lines":[2,3,4,5,6,7,8,9,10,11]}
2015/07/11 17:22:28 [
  {
    "op": "replace",
    "path": "/Lines/0",
    "value": 2
  },
  {
    "op": "replace",
    "path": "/Lines/1",
    "value": 3
  },
  {
    "op": "replace",
    "path": "/Lines/2",
    "value": 4
  },
  {
    "op": "replace",
    "path": "/Lines/3",
    "value": 5
  },
  {
    "op": "replace",
    "path": "/Lines/4",
    "value": 6
  },
  {
    "op": "replace",
    "path": "/Lines/5",
    "value": 7
  },
  {
    "op": "replace",
    "path": "/Lines/6",
    "value": 8
  },
  {
    "op": "replace",
    "path": "/Lines/7",
    "value": 9
  },
  {
    "op": "replace",
    "path": "/Lines/8",
    "value": 10
  },
  {
    "op": "replace",
    "path": "/Lines/9",
    "value": 11
  }
]

replace/add: JSON encoding omits Value if null

Hi @mattbaird,

RFC 6902 - 4.3 replace says:

[...] The operation object MUST contain a "value" member whose content specifies the replacement value. [...]

But the JsonPatchOperation struct JSON encoding for Value omits it if it's null:

type JsonPatchOperation struct {
	Operation string      `json:"op"`
	Path      string      `json:"path"`
	Value     interface{} `json:"value,omitempty"`
}

Proposing JsonPatchOperation implement json.Marshaller so it can emit a null value for the replace operation. Wdyt?

Thanks!

Can't create a patch for top level arrays

package test

import (
	"testing"

	"github.com/mattbaird/jsonpatch"

	"github.com/stretchr/testify/require"
)

func TestJSONPatchCreate(t *testing.T) {
	cases := map[string]struct {
		a string
		b string
	}{
		"object": {
			`{"asdf": "qwerty"}`,
			`{"asdf": "zzz"}`,
		},
		"array": {
			`[{"asdf": "qwerty"}]`,
			`[{"asdf": "bla"}, {"asdf": "zzz"}]`,
		},
	}

	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			_, err := jsonpatch.CreatePatch([]byte(tc.a), []byte(tc.b))
			require.NoError(t, err)
		})
	}
}

When I run the test above, the "object" case works, but the "array" case results in an error that states "Invalid JSON Document". Likely because jsonpatch.CreatePatch() tries to unmarshal into map[string]interface{} and doesn't try to unmarshal into []interface{}

apply patch

found that we have two solutions on go for jsonpatch, one generates and the other one applies, made a humble attempt at joining them here still needs:

would appreciate any feedback or help on this one

Thanks 🏭

Please adjust the array "remove" operations’ order in the patch result

Different from other operations, the array "remove" operations’ order should be descending by path index.

Origin: [{"id": 1, "title":"news 1"}, {"id": 2, "title":"news 2"}, {"id": 4, "title":"news 4"}]
Target: [{"id": 1, "title":"news 1"}, {"id": 3, "title":"news 3"}]
Current patch: [{"op":"remove","path":"/1"},{"op":"remove","path":"/2"},{"op":"add","path":"/1","value":{"id":3,"title":"news 3"}}]

It's better to be:
[{"op":"remove","path":"/2"},{"op":"remove","path":"/1"},{"op":"add","path":"/1","value":{"id":3,"title":"news 3"}}]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.