GraphQL vs REST: putting the two to the test

What is REST?

REST stands for Representational State Transfer and it’s an API design approach that is commonly used for building web services. REST API relies on a predefined set of stateless operations that allow us to retrieve and manipulate data.

The main concept of REST is the resource, i.e. any object about which the API can provide information. Each resource has its own, unique identifier that can be accessed by sending a proper request to the server. The most-commonly-used methods which enable the client to take actions on those resources are:

  • GET – retrieves a representation of a resource. This method is used only to fetch the data.
  • POST – creates new subordinate resources.
  • PUT – updates a given resource with the request body or creates a new resource.
  • DELETE – deletes a resource identified by a URI.

Over the past few years, several principles have emerged that we should keep in mind while creating REST API. Currently, we distinguish six constraints which should be fulfilled:

  • Uniform Interface – says that the interface should provide standardized communication between the client and the server.
  • Client-server – means that the implementation of the client and server must be done independently.
  • Stateless – presupposes that each request must have a complete set of information necessary for its proper execution.
  • Cacheable – API should support data caching to increase performance.
  • Layered System – the system should be designed in such a way that the client can get the answer without having knowledge of what is happening on the server.
  • Code on demand (optional) – this principle refers to the possibility of sending code fragments that can be executed on the client-side.

REST API has become the unofficial standard when it comes to creating API but just like any other solution, it has both pros and cons. Let’s stop for a moment and take a closer look at them.

REST API benefits

To start on a good note, let’s begin with advantages.

  • Convenience to use

One of the major benefits of the REST is its supportability. Data is not associated with a particular resource or method, which allows handling various types of calls and returning different data formats, including JSON, HTML, XML, YAML, or plain text. This allows developers to build an API that meets the requirements of different types of customers.

  • Scalability

The next thing is the infinite scalability of REST which results from the client-server architecture it offers. A clean separation of both client and server results in quick and efficient scaling of the digital product.

  • Independence

Last but not least, REST API is not language programming-specific. It is just an abstraction of functionality, thus it’s highly adaptable. With REST API you can have Node.js, Python or PHP servers. Moreover, you don’t need to install any framework or library on the client-side of your application to make it work. The only effort you have to make when starting to work with the API is to make a simple request to the target service.

Have you ever wondered how to use Elasticsearch with Django and REST Framework? Say no more, here’s the answer!

REST API limitations

Let’s now dive into some limitations of the REST architecture, shall we?

  • Multiple round trips

Over the decades, the requirements of the clients using REST APIs have changed. Currently, most applications use data that typically comes from various sources. As a result, it may happen that we need to make multiple requests to get all the information we are interested in.

Let me prove my point with an example of a blogging app. Imagine you need to display the name and the role of the particular user together with a list of articles written by them. How would you do that? In a typical REST API, you probably access an endpoint that returns initial user data and then hit another endpoint in order to fetch all articles for a given user.

GET /users/1
{
"id": "1",
"name": "John",
"role": "JavaScript Developer",
"location": "Poznan",
}GET /users/1/articles
{
"articles": [{
"id": "1",
"title": "A very interesting article!",
"comments": "[...]",
}]
}

As you can see, it takes two requests to complete one simple task.

  • Over and under-fetching

The second major drawback is closely connected to the former example. As you can see above, performing our task we retrieved additional information that we didn’t actually need, namely location. That kind of situation is called over-fetching and arises from the fact that endpoints return only fixed data structures. The opposite situation, when the endpoint is not providing all the information we need is termed under-fetching. This is a very simplified example, but it’s not hard to imagine a large application that is fetching a lot of unnecessary data and we definitely don’t want that.

What is GraphQL?

Now, let’s take a look at relatively new technology (especially as compared to REST), which is GraphQL. It’s a stateless, client-independent API design architecture for exchanging data that’s based on high-flexibility queries. Unlike the REST API, GraphQL isn’t dealing with the concept of a resource. Instead, a set of information is treated as a graph and therefore every object is connected with each other.

One of the most striking things about the GraphQL vs REST duel is that when you use the former solution, you’re limited to sending one kind of request only. That’s a POST request (even for getting data) to an endpoint typically named /graphql. What’s the reason behind this? GraphQL defines its own query language in order to retrieve the data you need. Queries are then included as a body of the request and since the GET method can’t have a request body, we simply can’t use it. This is how a typical query looks like:

{
query {
user {
name
role
}
}
}

It’s a structure that can remind you of JSON or YAML file and consists of operation type (in this example, query), endpoint (user), and the fields you want to extract (name, role). It’s worth noting that there are three different types of operations here:

  • Query – retrieves data (think of it as a GET request in REST API).
  • Mutation – manipulates data (corresponds to such methods as POST, PUT, and DELETE).
  • Subscription – sets up a realtime connection via WebSockets.

GraphQL’s declarative approach makes it super easy to understand. It’s safe to say that we’re basically writing JSON objects without values. But that’s not the only advantage of this technology...

GraphQL benefits

  • Flexibility

What makes GraphQL interesting is also flexibility – because it eliminates multiple round trips to the server, it gives developers an opportunity to fetch the needed data with no more than a single call. To prove my point, let me refer to the issue I mentioned while discussing REST API limitations. In this case, if you want to display the name and role of the user and a list of user’s articles, you’d simply create a single GraphQL query that includes only data that meets your expectations.

query {
User(id: "1") {
name,
role,
articles {
title
}
}
}

Next, the server is returning a response with a JSON object.

{
"data": {
"User": {
"name": "John",
"role": "JavaScript Developer",
"articles": [{
"title": "A very interesting article!",
}],
}
}
}

It’s very simple and flexible, isn’t it?

  • No over and under-fetching problem

As you can see, GraphQL solves over-fetching and under-fetching problems as shown in the previous section by obtaining no more and no less, but just the right amount of data you need in a single request. It’s a clear win in this aspect of the GraphQL vs REST battle.

  • Rapid product iterations on the client

Another major advantage is that using GraphQL allows for rapid iterations on the frontend. With every change connected to the UI, there is a risk that a new piece of information will be required. Thanks to the abovementioned flexibility, changes can be applied to the client-side of the application without any additional work on the server.

  • Subscriptions

When following the REST architecture, API can perform only certain operations using a predefined set of stateless operations such as GET, POST, or DELETE. In addition to that, GraphQL introduces a brand new operation known as a subscription. It allows the client to receive real-time messages from the server. An example? Notifying the client when a new user has registered in an application.

GraphQL limitations

There is no such thing as technology without drawbacks and GraphQL is no exception to this rule.

  • Problems with caching at the network level

The first disadvantage of GraphQL is the lack of built-in caching at the network level. Cache implemented at the HTTP level can reduce the amount of traffic to a server by keeping frequently accessed resources close to the client. In this case, it won’t be available out of the box because of using a single endpoint with many different queries. Therefore, the developer is responsible for the correct implementation of caching.

  • Performance with complex queries

The next thing is the performance of GraphQL. Queries can encounter performance bottlenecks if a client asks for too many nested fields at once. For more complex operations you should consider a REST API as it might be more straightforward if you’ve defined endpoints for a specific need.

  • Syntax on frontend and backend

Then, GraphQL query syntax is required to be exactly the same on the frontend and backend. While this is not an issue in itself, the real problem emerges when one side of the application, let’s say the backend, requires some specific syntax or maybe an extra nesting. In this case, you have to write redundant code on the other side of the application in order for queries to be equal.

That situation can occur if you use Relay GraphQL client – your server must then follow the Relay specification which requires two specific keywords on every nested level, node and edges. In the wake of these requirements, you write some extra code that could be omitted when using a different client. Look at how long the query below (which comes from Relay-powered app) is:

query {
allCategories {
edges {
node {
name,
ingredients {
edges {
node {
name
}
}
}
}
}
}
}

  • Error reporting and monitoring

Parsing server errors is much more complicated when using GraphQL because it always returns 200 status code. An example GraphQL error could look like this:

HTTP 200 OK

{
errors: [
{
message: 'No user found'
}
]
}

As you can see, the error response is difficult to handle compared to REST, where you can benefit from all the HTTP response statuses.

GraphQL vs REST: and the winner is...

GraphQL is a breath of fresh air in a world dominated by REST architecture. It’s exciting to use and it looks like it could be a reliable alternative to the current trends in API creation. Its flexibility and the high speed of query execution make it an interesting alternative to REST. However, it would be unfair to say that it's the obvious winner of the GraphQL vs REST battle.

Both solutions boast certain advantages and will work well in different use cases. GraphQL is going to shine when you need rapid development on the frontend and you expect the application to be responsive and with low latency. REST, on the other hand, is a more suitable solution for more complex applications with lots of caching and error reporting. It all boils down to your needs. To be able to clearly assess them and understand the difference, you simply need to understand the tradeoffs and decide on your own.

Looking for personal growth and programming challenges? Check our job offers and join Merixstudio!

Navigate the changing IT landscape

Some highlighted content that we want to draw attention to to link to our other resources. It usually contains a link .