Subject: [apps-discuss] Updated JSON Merge Patch...

From: James M Snell <[email-masked]>
Date: Thu, 4 Oct 2012 11:54:51 -0700

I have refreshed the JSON Merge Patch draft...

  http://www.ietf.org/id/draft-snell-merge-patch-04.txt

This is an alternative/complement to JSON-Patch derived from a number of
different specific implementations in the wild.

Example, given the original document:

  {
    "a": 1,
    "b": 2,
    "c": 3,
    "d": {
      "e": 4,
      "f": 5,
      "g": 6
    }
  }

Merge-patch allows us to perform a partial modification by example, rather
than explicit list of change operations:

  PATCH /doc HTTP/1.1
  Host: example.org
  Content-Type: application/json-merge-patch

  {
    "a": 0,
    "b": null,
    "d": {
      "i": 7
    }
  }

Which would yield:

  {
    "a": 0,
    "c": 3,
    "d": {
      "e": 4,
      "f": 5,
      "g": 6,
      "i": 7
    }
  }

As always, feedback is quite welcome.

- James

---

From: "Manger, James H" <[email-masked]>
Date: Mon, 8 Oct 2012 18:36:19 +1100

Comparing draft-snell-merge-patch and draft-ietf-appsawg-json-patch:

I like this merge-patch syntax. It effectively supports 2 operations:
1. Removing a JSON object element
2. Adding a JSON object element

Both operations work regardless of the current state of the JSON doc. Removing an item that doesn't exist is not an error, it's just does nothing. Great! Adding an item replaces an existing item, or creates a new item, or even creates new parent objects for the item as required -- it is never an error. Great!

The operations in ietf-appsawg-json-patch should have similar semantics.
{"op":"remove", "path":"/a/b/c"} shouldn't cause an error if /a/b/c doesn't exist.
A "put" operation should ensure that after the op is applied the given value exists at the given position -- regardless of whether it has to replace an existing value, create a new value, or even create intermediate objects.

Apply {"op":"put", "path":"/a/b/c", "value":2}

To {"a":{"b":{"c":1}}} should give {"a":{"b":{"c":2}}}

To {"a":{"b":{"foo":"bar"}}} should give {"a":{"b":{"foo":"bar", "c":2}}}

To {"a":{"x":"y"}} should give {"a":{"x":"y", "b":{"c":2}}}

[The one extra rule we need is that only intermediate objects are created, never intermediate arrays, even if a segment of the "path" is "/0".]

--
James Manger

---

From: "Manger, James H" <[email-masked]>
Date: Tue, 9 Oct 2012 12:15:44 +1100

Comments on draft-snell-merge-patch-04:

The introduction tries to distinguish an “explicit description of the changes” and “a modified subset” of the resource. I don’t like this characterization as a merge-patch doc is clear about its changes. The key features of merge-patch are its limited operations, and special-casing of null, that allow a merge-patch value to look a bit like a subset of the doc it is patching.

My attempt at an intro:
“The merge-patch format supports two types of changes: removing and setting JSON object elements. JSON arrays are treated the same way as JSON primitives: the whole value can be replaced, but not partially modified. The JSON null value is given a special meaning. These constraints allow merge-patch to use a format that closely mimics the document being patched. The constraints mean merge-patch is suitable for patching JSON documents that primarily use objects for their structure, and don’t use null values. The merge-patch format is not appropriate for all JSON syntaxes.”

Much of the current intro appears to be a convoluted motivation for why merge-patch needs its own media type. I would drop all that and just state that “application/json-merge-patch” is the media type for this format. I don’t think any further motivation is needed. The “patching-a-patch-format” argument is cute, but move it to an appendix if you really want to keep it.

The example is appalling (not merely “somewhat extreme” as the intro says). The example is patching a json-patch doc. A json-patch is always an array. Merge-patch cannot “patch” an array, it can only completely replace it. In this situation, any PATCH with a merge-patch value should be done more simply with a PUT of a new json-patch value. The example was only intended to illustrate a media type corner-case, but being in the introduction it will be seen as an example of merge-patch.
[P.S. Sending the merge-patch with the json-patch media type wouldn’t result in “an unintended modification” in this case. It would trigger an error.]
[P.S. Some json-patch “path” values should be “/title”, not “title”.]

Does application/json-merge-patch really need a charset parameter? I much prefer the JSON approach: MUST be Unicode [http://tools.ietf.org/html/rfc4627#section-3].

The change rules are not quite right. Consider these cases:
Merge-patch       Old       New       Comment
{"a":2}           [0,1]     {"a":2}   not really covered
{"a":{"b":null}}  {}        {"a":{}}  text almost says New is {"a":{"b":null}}

--
James Manger

From: James M Snell [mailto:[email-masked]]
Sent: Tuesday, 9 October 2012 2:03 AM
To: Manger, James H
Subject: Re: [apps-discuss] Updated JSON Merge Patch...

True... I've actually been considering tightening that language up a bit more to get rid of the fuzz.
On Mon, Oct 8, 2012 at 12:51 AM, Manger, James H <[email-masked]<mailto:[email-masked]>> wrote:
Comments on draft-snell-merge-patch-04:

The syntax (any JSON) and semantics of an application/json-merge-patch doc look well-defined and unambiguous. An implementation could apply any patch to any JSON doc. The spec text, however, seems to imply that the changes are somehow fuzzy, depending on the servers "understanding of the target resource media type and the underlying data model".

I can understand that a server may want to accept or reject a specific set of changes based on resource-specific knowledge. But that is true of any HTTP request, and is supported by status codes (eg 201 Created vs 400 Bad Request).

--
James Manger