-
Notifications
You must be signed in to change notification settings - Fork 890
Description
Issue #100 (and the discussion on #99 also) reveal an unresolved question in the spec, around how to properly form JSON Patch operations that remove an item from a to-many relationship. Currently, the spec says:
While to-many relationships are represented as a JSON array in a GET response, they are updated as if they were a set. [...] To remove an element from a to-many relationship, use a
remove
operation onlinks/<name>/<id>
.
This is problematic because JSON Pointer (RFC 6901), the address format for JSON Patch's (RFC 6902) path
, makes no mention of sets, only arrays. Consider the following example resource, a post with 4 comments:
{
"posts": [{
"id": "1",
"links": {
"comments": [ "1", "3", "5", "7" ]
}
}]
}
The current JSON API spec says that if we want to remove the comment with ID 3, we'd make the following PATCH
request:
PATCH /photos/1
[
{ "op": "remove", "path": "/posts/0/links/comments/3" }
]
This is a valid JSON Patch document, but its standard semantics are different from what the JSON API spec would have it mean. A naive client built on a compliant JSON Patch library could very easily make the above request with the intention of removing the element with index 3 in the comments
array (i.e., comment 7), but instead, our JSON API-compliant server would remove the wrong comment, comment 3.
I propose that in order to remove an element from a to-many relationship, a client must use a remove
operation on links/<name>/<arrayIndex>
, along with a test
that links/<name>/<arrayIndex>
has the value we expect. With our example from above, this would look like:
PATCH /photos/1
[
{ "op": "test", "path": "/posts/0/links/comments/1", "value": "3" }
{ "op": "remove", "path": "/posts/0/links/comments/1" }
]
This is guaranteed to always be safe, and also complies with both the JSON Patch and JSON Pointer specs. For more info on the test
operation see RFC 6902, §4.6.