Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New JSON Patch Operators and Modifiers #14

Open
huggsboson opened this issue Sep 7, 2015 · 2 comments
Open

New JSON Patch Operators and Modifiers #14

huggsboson opened this issue Sep 7, 2015 · 2 comments

Comments

@huggsboson
Copy link

We've loved using the JSONPatch specification thus far and have built a number of internal and external APIs to use it. I wanted to get your thoughts on a few additions we will be pursuing to the JSONPatch spec (using a different content-type application/vnd.box.json-patch+json).

You are already aware of our desire for a strict-add operator and put it on the json-patch2 issue list. We are going to use patches to help us describe migrations on json which have a number of optional fields. We ended up wanting to make sure that everything made sense and was consistent with the existing set of operators and easy to reason about. Also we are contemplating a few new operators for dealing with paths with certain values.

Before I jump in, I realize this ups the complexity of the spec a bit, but we actually have need for each and everyone of these new operators and new modifiers. Some of the combinations of operators and modifiers aren't really needed for us, but we wanted to specify them fully to ensure that the convention we described actually generalizes properly.

Modifiers

The rule we've found when studying the existing operators is:
Operators throw if source does not exist and do not care if dest exists or does not exist

What we are looking to do is add a number of new operators that follow this naming convention:
A suffix on operators for modifiers on source:
? = skip if source does not exist

A suffix on operators for modifiers on dest:
! = throws if dest exists

  • = skip if dest exists

Here's a helpful model for understanding:
screen shot 2015-08-31 at 3 37 56 pm

add: { "op": "add", "path": "/foo", "value": "bar" } -- destination only
add -- overwrite dest either way
add! -- throw if dest is exists (aka the-one-true-add)
add* -- skip if dest exists (aka default operator)

remove: { "op": "remove", "path": "/foo" } -- source only
remove -- throw if source is missing otherwise delete
remove? -- skip if source is missing

replace: { "op": "replace", "path": "/foo", "value": "bar" } -- source only
replace -- throw if source is missing otherwise replace value
replace? -- skip if source is missing

copy: { "op": "copy", "from": "/foo", "path": "/bar" }
copy -- throws if source does not exist otherwise set or overwrite
copy? -- skips if source does not exist
copy! -- throws if dest already exists
copy* -- skips if dest already exists
ban: copy?! -- throw if dest exists or skip if source is missing
ban: copy?* -- skip if source does not exist or dest does exist

move: { "op": "move", "from": "/foo", "path": "/bar" }
move -- throws if source does not exist
move? -- skips if source does not exist
move! -- throws if source already exists, throws if dest already exists
move* -- skip if dest already exists
...

test: { "op": "test", "path": "/foo", "value": "bar" } -- source only
test -- throws if does not exist or is not equal value
test? - skips if source does not exist
!test -- throws if does not exist or value is equal, special.
!test? -- skip if source does not exist or throw if value is equal, special.

New Operators

We are also looking to add some new base operators: exists, translate, omit.
exists: { "op": "exists", "path": "/foo" } -- source only
exists -- throws if source does not exist
!exists -- throws if source exists, special.

translate: { "op": "translate", "path": "/foo", "from": "bar", "value": "baz" } -- source only
translate -- translates values at path that match "from" to "value"
translate? -- skip if source does not exist

omit: { "op": "omit", "path": "/foo", "value": "bar" } -- source only
omit -- remove the property or item if it matches value, throw if source does not exist
omit? -- skip if source does not exist

So yeah, I know you are pretty open to extensions as long as we are clear about the content-type. I'd just love any feedback you have about the design choices we've made so we can avoid deviating too much from any future plans you have.

@konrad7d
Copy link

+1 especially for the ability to test for element non-existence (the "!exists" keyword).

@mitar
Copy link

mitar commented Oct 12, 2019

I think this is adding to much complexity to JSON patch. I think JSON patch should just provide a diff against a known version of base JSON and then external algorithms should be used to fuzzy-apply this if base JSON does not exactly match. I would suggest that JSON patch only standardizes some ways to provide more operation-level and global-level context to help with such fuzzy-apply algorithms.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants