2

We need to update a counter through our REST API and we're using JSON Patch for our PATCH calls, so it should be something like this:

{"op":"increment", "path":"/counter", "value": 1 }

The problem is JSON Patch doesn't support this type of operation. ADD operation is only supposed to work with arrays, so the closest solution would be to use the REPLACE operation to replace the counter value, but that could result in problems if more than one client tried to update the counter at the same time.

So how should we tackle this problem and how wrong would it be to add a custom operation like increment ?

2 Answers2

2

Even though the standard doesn't support this that doesn't change the fact this is a very valid use case.

Case in point CosmosDB has added support for this highly requested feature: https://learn.microsoft.com/en-us/azure/cosmos-db/partial-document-update#supported-operations

I do not agree with the accepted, opinionated, answer. Standards and specs are not infallible.

Due to the spec limitation your best option in my opinion is to create a new specialized increment operation.

atomaras
  • 2,468
  • 2
  • 19
  • 28
1

The problem is JSON Patch doesn't support this type of operation. ADD operation is only supposed to work with arrays, so the closest solution would be to use the REPLACE operation to replace the counter value

replace is the correct answer.

that could result in problems if more than one client tried to update the counter at the same time.

Take a careful look at test, which gives you the semantics necessary to describe a precondition. In effect, your document becomes a description of a compare and swap.

how wrong would it be to add a custom operation like increment ?

All the way wrong. RFC 6902 clearly states that the set of operations MUST NOT be extended

Operation objects MUST have exactly one "op" member, whose value indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors.

You could, of course, define a new specification that includes the operators that you need. But there won't be nearly as much tooling your own vanity patch documents.

In the larger picture, if you are trying to communicate "increment" as opposed to "set", then remote authoring semantics may not be the right choice -- the problem may be trying to tell you that you have the wrong tool in your hand.

Community
  • 1
  • 1
VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • How would that compare and swap work ? Would the document be something like this ? { [ {"op":"test","path":"counter","value":40}, {"op":"replace","path":"counter","value":41} ] } – smoothoperator96 Jan 14 '20 at 21:07
  • Something very like that, yes. – VoiceOfUnreason Jan 14 '20 at 21:32
  • The add is not restricted to the lists: "The "add" operation performs one of the following functions, depending upon what the target location references: If the target location specifies an array index, a new value is inserted into the array at the specified index. If the target location specifies an object member that does not already exist, a new member is added to the object. If the target location specifies an object member that does exist, that member’s value is replaced." from the RFC. I understand that the add done on an existing value is equivalent to the replace. – user1708042 May 06 '21 at 14:38