To help consumers update resources in as specific and intentional way as possible, we've begun rolling out endpoints that support "JSON Patch" as described by IETF RFC 6902. A JSON Patch request allows you to describe changes to be made to a resource rather than sending the full definition of a resource.
More details about JSON Patch (including links to useful libraries) can be found at https://jsonpatch.com/
Simple Example
The original resource:
{
"customer": {
"name": "Jim Gordon",
"email": "[email protected]"
},
"orders": [
{
"orderNumber": 121,
"amount": 123
},
{
"orderNumber": 122,
"amount": 37
}
]
}
The JSON Patch:
[
{
"op": "replace",
"path": "/customer/email",
"value": "[email protected]"
},
{
"op": "add",
"path": "/orders",
"value": {
"orderNumber": 123,
"amount": 42
}
}
]
The final document:
{
"customer": {
"name": "Jim Gordon",
"email": "[email protected]"
},
"orders": [
{
"orderNumber": 121,
"amount": 123
},
{
"orderNumber": 122,
"amount": 37
},
{
"orderNumber": 123,
"amount": 42
}
]
}
EveryAction 8 Requirements
We've added a few requirements on top of standard JSON Patch that help to make sure consumers are updating exactly the things they're interested in updating.
Array Pointer Tests
JSON Patch uses JSON Pointers which can point to specific items in a collection using zero-based indexing. In the example above, we could refer to the amount of Order Number 122 as /orders/1/amount
. Because sort order isn't always guaranteed nor can we guarantee another user won't add another item to a collection between the time you determine the array index and make the PATCH
call, we require all such operations to be accompanied by a test
operation that verifies a value at the target.
In the example above, if we wanted to change the amount
of Order Number 122, we'd send two operations. The first tests a unique value on the object at position /orders/1
to verify it's the one we want to update. The second changes the value of amount
.
[
{
"op": "test",
"path": "/orders/1/orderNumber",
"value": 122
},
{
"op": "replace",
"path": "/orders/1/amount",
"value": 78
}
]
Operations are sequential
If you're using array pointers and you
remove
an item, keep in mind that the array index of all remaining items will change.
test
value at position0
remove
item at position0
replace
item at position0
-- was previously the item at position1
Content-Type Header
Because JSON Patch documents are valid JSON, we will continue to accept application/json
as the Content-Type
. We will ignore application/json-patch+json
.
Not all properties are patch-able
Not all properties of an object are patch-able. And the properties that are patchable may vary depending on the endpoint. For example, you can change the Campaign of Code by patching /campaign/campaignId
but you can't use the same endpoint to change the name of that campaign.
The properties that are patchable will be listed in the individual endpoint's documentation.
Errors
You could come across a couple JSON Patch specific errors. If you look at the hint
property of the error you'll get more information about what needs to be done to remedy the issue.
Does not exist or can't be patched
If you try to patch a property that we haven't enabled patching for, you'll get a validation error like:
{
"errors": [
{
"code": "INVALID_PARAMETER",
"text": "'path' '/supportedEntities/0/name' does not exist or cannot be patched in this context.",
"properties": [
"operations[0].path"
]
}
]
}
Must also specify a test
op
test
opIf you're trying to patch a property with an array index but don't include a test
operation (described above), you'll get a validation error like:
{
"errors": [
{
"code": "INVALID_PARAMETER",
"text": "When using the 'replace' op on '/supportedEntities/0/name' in 'path', you must also specify a corresponding 'test' op for '/supportedEntities/0'",
"properties": [
"operations[0].path"
],
"hint": "Using a 'test' ensures that the position of the item you intend to modify has not changed positions."
}
]
}
Not equal to the test value
If you include a test
operation (described above) and the test fails, you'll get a validation error like:
{
"errors": [
{
"code": "INVALID_PARAMETER",
"text": "The current value 'Cats' at path 'name' is not equal to the test value 'Dogs'.",
"properties": [
"operations[0]"
]
}
]
}