Patch for JSON Api

“closeup photo of eyeglasses” by Kevin Ku on Unsplash

Anyone who has worked with JSON Api and conforming to it’s format might be familiar with the problem of supporting JSON Batch creates/updates. Well, it’s just not supported. Not at the moment. We have, in Blinkist, have a slight problem with formulating methods to have an efficient but consistent way of processing batch requests.

We have looked at how Mailchimp, Facebook, Asana and Google try to do this. This post tries to pave light on the ways how we might achieve this.

Circumventing the JSON Api restriction

The first option we thought of is to create a wrapper around.

Say we have a model Car. A representation of this model in JSON Api terms could be

{
"type": "cars",
"id": "1",
"attributes": {
"name": "BMW 5 Series",
"engine_number": "HJOIJ18HZYX89"
}
}

Now if we think of an App which creates/updates data on this API, it would make sense for the App to store things locally first and sync when it has bandwidth (mobile networks for sync is a strict NO). Which essentially means we must do either
* Send X requests for X sync items
* Send 1 batch request with X items in the batch

Well, in JSON Api terms, we could send a POST/PUT to something like

{
"type": "car_batches",
"attributes": {
"operations": [
{
"type": "cars",
"attributes": {
"name": "BMW 5 Series",
"engine_number": "HJOIJ18HZYX89"
}
}, {
"type": "cars",
"attributes": {
"name": "BMW 3 Series",
"engine_number": "HPPOIA18HZYX89"
}
}
]
}
}

Some features about this implementation

  • Specific to the Model — Every model that you need a batch operation should have an implementation of model_batches
  • Bound to the Service — If we were to think of a service which takes care of the CRUD of the Cars model, then the batch becomes part of this Service. It knows how to CRUD the Car and it does not need to ask anyone else.
  • Route specific to the Service — The route to the Resource might be /car_batches and is not generic
  • Background processing — It might or might not implement it. We could just as well, loop through the whole list and do a CRUD with respect to the HTTP method of the batch
  • Bound to the HTTP method — We would only be able to do the same HTTP action on the batch items as we did on the batch itself. POST action on the /car_batches would mean create on the individual items of the batch.

Another sophisticated approach to decoupling the HTTP method could be conforming to the approach from JSONBatch. Observe that we do not need path as the operation is specific to a model.

{
"type": "car_batches",
"attributes": {
"operations": [
{
"operation": "create",
"value": {
"type": "cars",
"attributes": {
"name": "BMW 5 Series",
"engine_number": "HJOIJ18HZYX89"
}
}
}, {
"operation": "get",
"value": {
"type": "cars",
"id": "1"
}
}
]
}
}

The next post would be trying out a generic approach to our problem.