json-patch / json-patch2

A possibile revision to the JSON-Patch format
44 stars 0 forks source link

Possibility to add revision to operations #11

Open rkusa opened 9 years ago

rkusa commented 9 years ago

tl;dr I propose to add some special optional property to operations that indicate some kind of unique identifier or version/revision.

One scenario, where JSONPatch is really useful compared to working with complete states, are apps with collaborative functionalities.

Think of a collaborative application that is distributed through multiple servers, i.e., there are is no total order for incoming changes. For concurrent changes, one operation has to win against another and the result must be the same on every server.

That is, some operations need some kind of metadata. Taking for example the replace op. When implementing a map of data as a CRDT, one approach of doing so, is to track a version number for each property. This version number has to be included in the JSONPatch operation, e.g.:

{ "op": "replace", "path": "/foo", "value": "bar", "rev": 42 }

Another example is a OR-Set, which is, simply put, a list where (internally) each item has a unique id. A scenario where this is useful:

User A adds "foobar" (gets the unique id 123) to the list. Meanwhile another user, User B, also adds "foobar" (gets the unique id 456). However, User A immediately deletes its "foobar". This remove operation should not remove the "foobar" added by User B. In case of the OR-Set, User A removes "foobar" with the id 123 and therefore "foobar" with the id 456 is not affected.

I am currently solving this by creating operations as follows:

{ "op": "add", "path": "/list/123", "value": "foobar" }
{ "op": "remove", "path": "/list/123", "value": "foobar" }

However, without knowing that the underlying data structure of the list is a or-set an we are not working with an object, these operations are easy to get wrong.

I would propose to add some special optional property to operations that indicate some kind of unique identifier or version/revision.

tomalec commented 8 years ago

I have already specified the convention of Versioned JSON Patch https://github.com/tomalec/Versioned-JSON-Patch/blob/master/Versioned-JSON-Patch.md

The convention uses completely valid RFC6902 JSON Patch, version number storen in any given place in JSON document, and simply attaches this version in test + replace operation object for any JSON Patch sequence:

 [
     { "op": "test", "path": "/path/to/version", "value": 1 },
     { "op": "replace", "path": "/path/to/version", "value": 2 },
     { "op": "test", "path": "/a/b/c", "value": "foo" },
     ...
   ]

This let us build simple queue that makes sure that JSON Patch sequences are applied in correct order.

There is a

I have also defined multiple-versioned JSON Patch, for conflict resolution in concurrent, distributed environment: https://github.com/tomalec/Versioned-JSON-Patch/blob/master/Multiple-Versioned-JSON-Patch.md

Conceptually, it's the same thing, but requires a version node per each peer taking part in communication.

So far, for a year of extensive usage, it works like charm.

mnot commented 8 years ago

Take a look at HTTP ETags -- it's a way to assure that you don't overwrite changes without being so intrusive.

See: http://www.w3.org/1999/04/Editing/

tomalec commented 8 years ago

Thanks, But HTTP ETags solves it only when using HTTP, and we can use JSON Patch over other channels, even without network, so it would be nice to have versioning regardless of means of transportation.

Plus if the versions are in JSON Patch, the same entity which is responsible for applying it may decide how to handle queues/conflicts.

In regards, of being intrusive. It's Versioned JSON Patch, not Versioned JSON. So we need to add two operation objects to JSON Patch. In out implementation of Queue, version does not need to be real node of the JSON document, as queue layer may, once processed, just remove it from the patch to be applied on base document.

mitar commented 4 years ago

As I wrote in this comment in another issue I think versioning should be done at a different layer.

Maybe JSON patch could just reserve some keywords or explicitly allow adding more fields to the patch payload. The problem is that JSON is an array, Maybe we should make it an object with one property for steps of the patch, so:

{
  "context": <value>,
  "steps": [
    ...
  ]
}

This would make it much easier to extend. And add some global metadata to the whole set of steps. While additional metadata could go into each step as well.