Here’s a quick note from building a RESTful API for updating objects in my personal project.
Let’s say we have a transaction object with the following schema
{
"id": 911,
"amount": 100,
"currency": "INR",
"party": "UBER",
"note": "Cab from home to Indiranagar",
"tags": ["cab", "transport", "transit"]
"timestamp": "2024-01-12 20:08",
}
I want to create an API which allows modifying an existing transaction object. Modifications can be of 2 types.
- Completely replace a transaction
- Partially update a transaction, for eg; editing just the
note
field
I usually go with approach 1: creating a PUT /transactions/<id>
API that accepts a complete transaction object and replaces the existing one. This offloads most of the work to the client or caller, as they have to send the full transaction object even for minor changes. Most of the time that’s fine. But this time I wanted to explore other options.
Sending partial data in a PATCH
API
A PATCH /transaction/<id>
API that accepts a transaction object with only those fields that needs to be modified. Only the provided fields are updated in the database, while the rest remain unchanged. This is better in a way since the client doesn’t really need to know about the fields which are not being modified.
In this approach, deletion of fields should be handled carefully. Request body should be parsed correctly to distinguish between “not wanting to update a field” vs “deleting the existing value of a field”. Depending on the framework/language used for the API implementation, making this distinction might not be trivial.
To make this distinction clear, we can follow RFC 7386 - Here we explicitly set NULL
for those fields which needs to be deleted.
Callout
Arrays are treated as an atomic object when patching. This means they can only be replaced, not merged
If the patch is anything other than an object, the result will always be to replace the entire target with the entire patch. Also, it is not possible to patch part of a target that is not an object, such as to replace just some of the values in an array.
JSON patch document
A PATCH /transaction/<id>
API that will accept a PATCH document as specified in RFC 6902
According to the RFC, the document will contain 3 fields
op
- specifies the operation to be done (replace
,remove
,add
etc),path
- json path to the field to which the operation is to be performed,value
- actual content that needs to be used for the specifiedop
Example
[
{
"op": "remove",
"path": "/note"
},
{
"op": "replace",
"path": "/party",
"value": "Namma Yatri"
}
]
In this example, we do the following
- Replace the value at
/party
withNamma Yatri
- Remove the
/note
field
There are different libraries available in various languages to apply a PATCH
document to an existing object. An example in Go is evanphx/json-patch
Callout
RFC 6902 allows granular array operations using array indices in the path (e.g.,
/tags/0
for first element,/tags/-
to append etc). This enables precise array manipulation without replacing the entire array.
Summary
PUT
– when the client has full object knowledgePATCH
(RFC 7386) – when client wants to update a subset of fields simplyPATCH
(RFC 6902) – when fine-grained control is needed (e.g., arrays)