Skip to content

Instantly share code, notes, and snippets.

@amcgregor
Created January 17, 2022 16:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amcgregor/f18bcbb89ed472273bc24fe75d28024e to your computer and use it in GitHub Desktop.
Save amcgregor/f18bcbb89ed472273bc24fe75d28024e to your computer and use it in GitHub Desktop.
A comparison between jsonpatch.com and typical "parametric" operators for the same manipulations such as those provided by Marrow Mongo or MongoEngine.

You Don't Need JSON Patch

For simplicity sake, excluding the first example and the Test example, other parametric examples will be provided with a JSON representation for clarity. (Fun note, my WebCore web framework supports endpoint argument collection from a variety of data sources, including form-encoded POST, or JSON-encoded POST.)

The Original Document
{
  "baz": "qux",
  "foo": "bar"
}
The JSON Patch
[
  { "op": "replace", "path": "/baz", "value": "boo" },
  { "op": "add", "path": "/hello", "value": ["world"] },
  { "op": "remove", "path": "/foo" }
]
Parametric Version
POST / HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
baz=boo&push__hello=world&unset__foo

The JSON "patch" version includes complete objects describing the changes as an ordered list of operations to apply. HTTP form-encoded POST data is already ordered, and is already an explicit mapping of paths to values. "Parametric" simply encodes the operations themselves into the keys ("field paths") of the submitted data. And yes, form-encoded POST data does not require every key have a value. (Any "truthy" value could do, though.)

Operations

Add

Adding a value to an array would be a push operation, though the array manipulation capabilities can far exceed simple appending.

{"push__biscuits": "Ginger Nut"}
{"push__biscuits": "Ginger Nut", "push_pos__biscuits": 2}

Remove

Removing a specific key is fairly trivial.

{"unset__biscuits": true}
{"unset__biscuits__1": true}

Replace

Replacing a path is the default operation if no other operation is specified.

{"biscuits__0__name": "Chocolate Digestive"}
{"set__biscuits__0__name": "Chocolate Digestive"}

Copy

Currently Marrow Mongo (and MongoDB itself) does not provide an operation similar in functionality to this JSON Patch operation.

Move

{"rename__biscuits": "cookies"}

Test

Slighly complicated by virtue of the fact that HTTP already provides this functionality. There is absolutely no reason to include this in the definition of operations excepting for use outside the context of HTTP. But then you have multiple ways to accomplish the same thing under HTTP, which is un-good.

Testing is a form of filtering evaluation, which lands squarely into the realm of parametric querying operators. Under HTTP REST, these conditions would be specified as part of the query string when referencing the resource you are wishing to update.

POST /best_biscuit?name=Choco%20Leibniz HTTP/1.1
Host: example.com

If the best biscuit's name isn't Choco Leibniz the update will not proceed, and should return a 409 Conflict error status.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment