Why REST needs to rest

David Mohl
6 min readJul 9, 2015

RESTful APIs are currently a standard in the development field. They power everything, from mobile apps to websites over desktop apps and are flat out a good generic solution for delivering data. So what is the problem with that?

The REST model is flawed in that it doesn’t do enough for what applications have grown to need, and if it does enough, it does it too complex or not performant enough. But to go into detail why I think so, let’s take a look at some examples of REST that I believe to be the most common:

The ‘unnecessary strict’ approach

The strict approach is what is used when you try to keep every little piece of information separate. Rather than including data into one request, you tell the client instead where he can find that kind of information.

Imagine we have a social network. I call my rest API to fetch me my feed. Here’s what I could get back:

# /feed
{
“posts”: [
“/posts/1”,
“/posts/2”,
“/posts/3”,
]
}
# /post
{
“id”: 1,
“title”: “foo”,
“body”: “lorem ipsum”,
“author”: “/user/1”,
“comments”: “/posts/1/comments/”
}
# /posts/1/comments
[{
“author”: “/user/2”,
“body”: “cool article!”
}, …]

In this approach, doubled information is reduced to a minimum and each and every bit of data has their separate endpoint. While the API might look good, the client that wants to consume it has to jump over fences to get all the data he needs. Imagine a website with 30+ async requests that all fetch data and try to update the DOM once they got what they want. This will likely result in a lot of jumping and visible spinners.

You could (or have to) coordinate the requests to go in a certain order and only update the DOM once you have everything you need, but that itself is a painful task to implement. Add error handling for each and every endpoint on top and you have a proejct that is not a joy to work on. On top of that, keep in mind that each data endoint is generic and not for the exact module you are working on which means a lot of unnecessary data that adds to loading time and is getting thrown away.

The ‘all you can eat’ approach

With this approach, we do the exact opposite of what we did before. Instead of separating every information we have, we combine it and let the client consume everything at the same time. In our example from above, we would include comment, author and userdata into the same endpoint and return a more atomar set that could stand by it’s own.

The problem with this approach is what the first approach tried to get rid of: Duplication of data. The comment endpoint includes the users information and the post endpoint includes a own set of comments and user information. This often results in very big json objects that need to get downloaded before anything can happen. You might not have to coordinate as much on the frontend, but you pay the bill with waiting. Waiting for cases where you need around 40% of the data inside the json but someone on the backend decided to dump all keys available in it.

The ‘hybrid’ approach

On this approach, we create different endpoints for different things we want to achieve. For example we could have a /list endpoint for posts, but also a /user_profile endpoint that includes all posts by the user to show it inside a profile page. This endpoint inherits all the things I wrote above about duplication of data and more than once, each endpoint includes their own keys. Comments in the /list endpoint might include a timestamp but comments inside /user_profile might not because it is not needed on that page.

The bigger problem

Each of these approaches have a obvious downside. The strict approach will keep data separated but requires a lot more work on the frontend. The combined approaches serve everything at once but have bigger waiting times. The hybrid one is more product centric but duplicates data a lot. But are these problems really that difficult to solve?

The bigger problem with REST is development time. We either write the API or the client upfront. In any way, one component will have to wait for the other to implement functionality that the other already provides.

Here’s another case: Let’s imagine our social network needs some work and we want to implement the time of when a comment got posted next to it. In the strict approach, we add that information to the comment endpoint and adjust the client to consume it, not that big of a deal (given that we already wrote 2000 lines of code to coordinate all the requests). But in the combined approaches, we will end up touching /comments /posts /user_profile /detail and, well, every other endpoint that includes comments. One single change could end up cascading through our entire application.

The solution

To summarize, we don’t want big endpoints and we don’t want to coordinate the hell out of everything. We also don’t want small changes to cascade through our entire project, so what can we do here?

This is actually a very common problem that many big companies already had to face. One solution many came up with independently is a more descriptive approach, which brings us to facebook. Facebook recently introduced GraphQL, a technology they used for nearly 3 years! So what is GraphQL? To summarize it, let me quote their blog post:

A GraphQL query is a string interpreted by a server that returns data in a specified format.

In GraphQL (or any other reactive approach), the client takes control in what information he needs and not the server. Rather than 50 endpoints, we have one that is able to parse the users request and return data in the exact format the client requested it in. We no longer have to take care of implementing new endpoints, updating old ones or worry about cascading effects a change could have. All we have to take care of now is authorization and parsing (very simplified case).

Facebook is actually not the first company that came up with this kind of approach. Netflix introduced ‘Falkor’ at around the same time completely independent of facebook. Falkor does a very similar thing — it shifts the focus to the client that consumes the data and away from the server that provides it. After all, we want to write applications and not parsers and fetchers for data.

So what are advantages of GraphQL-like approaches?

  • We don’t need to care about endpoint maintenance
  • The client that is consuming the data specifies the response
  • Backwards compatibility — we don’t need to versionize our endpoints for older versions of the app as the old app specifies needed data itself
  • Shorter responses. We will only get the data we need and not overhead that the app doesn’t use but ‘is nice to have’.
  • More time on actual product development and less time spent on the API

Should we start re-writing our REST APIs into GraphQL-like APIs? Probably in the future? Why not. These kind of approaches try to solve the problems that REST has and implement a more intuitive, more time saving approach to application development.

So next time when you bootstrap a new project at your company, don’t pick REST blindly. Think about the future scope of your app and where your focus is. After all

REST is intended for long-lived network-based applications that span multiple organizations.

according to it’s inventor. (which I shamelessly stole from facebooks blog post).

--

--

David Mohl
David Mohl

Written by David Mohl

Tokyo based engineer with a slight obsession for productivity. In love with photography, videography and programming. Constantly improving.

No responses yet