Avoid over-fetching with GraphQL
10 July 2022 in Blog,PayTechTalk
by Ludovic Plisson
Share This Story, Choose Your Platform!
In a nutshell
The goal of this article is to point out the over-fetching issues you may encounter with a RESTful API, and how to avoid it with GraphQL.
This article is not about developing or using a GraphQL API. If you want to go further and try it by yourself, you can follow this excellent tutorial by Robin Wieruch.
Over-fetching is over
Most of the web APIs are designed following the REpresentational State Transfer (REST) architecture. It has been the standard for a couple of decades now, but it comes with some drawbacks. One of the most mentioned is over-fetching.
A RESTful API exposes several endpoints allowing to interact with the different entities composing your data.You can make HTTP requests with different methods to Create (POST), Read (GET), Update (PUT) or Delete (DELETE) those entities.
In this article we will focus on the GET method which allows two main ways to query your data:
- HTTP GET /users will give you the list of users.
- HTTP GET /users/<ID> will give you a specific user given its ID
In the REST queries, all the data about our users is retrieved, even informations we do not want to use on our page. This is the over-fetching issue we want to fix.
An API using GraphQL exposes only one endpoint (/graphql by default) which can only get called with the POST method. To define the required data, the body of the request will contain a request written in the query language called GraphQL.
Say we have a blog with the following users:
{
users : [
{
id: 1,
firstName: "Amy",
lastName: "Sears",
age: 38,
[...]
},
{
id: 2,
firstName: "Stephen",
lastName: "Peterson",
age: 27,
[...]
},
[...]
]
}
We want a page where our users are listed by their names.
REST query:
GET /users will return:
[
{
id: 1,
firstName: "Amy",
lastName: "Sears",
age: 38,
[...],
},
{
id: 2,
firstName: "Stephen",
lastName: "Peterson",
age: 27,
[...]
},
[...]
]
GraphQL query:
POST /graphql with body
{
users {
firstName
lastName
}
}
will return:
{
users: [
{
firstName: "Amy",
lastName: "Sears",
},
{
firstName: "Stephen",
lastName: "Peterson",
},
[...]
]
}
You might have noticed that we have to explicitly ask the fields firstName and lastName in the GraphQL query. That is because as said above, the required data is defined in the body of the query, and on our page, we only want to show our users names.
Our users have written articles, we now have the following data:
{
users : [
{
id: 1,
firstName: "Amy",
lastName: "Sears",
age: 38,
articles: [1, 2],
[...]
},
[...]
],
articles: [
{
id: 1,
title: "Last night versioning saved my life",
[...]
},
{
id: 2,
title: "Webstorm vs Visual Studio Code vs Gedit",
[...]
},
[...]
]
}
If we want to get a user name and his articles titles in REST, we have several possibilities:
- We can add the articles informations inside the dataset of our endpoint response
GET /users/1 will return:
{
id: 1,
firstName: "Amy",
lastName: "Sears",
age: 38,
articles: [
{
id: 1,
title: "Last night versioning saved my life",
author: 1
[...]
},
{
id: 2,
title: "Webstorm vs Visual Studio Code vs Gedit",
author: 1
[...]
},
[...]
],
[...]
}
But if we do that, any query on a user will return these informations, even if we don’t need them, so we are over-fetching.
- We can first call /users/1 to get our user informations, including the IDs of the articles he wrote, then call /articles/1 and /articles/2
that will induce a waterfall of network requests.
- We can also create a new endpoint /user-with-articles/<ID> to avoid polluting our /users/<ID> request.
On a sophisticated API, this will quickly lead to a lot of endpoints that can be misleading for the client.
With the following GraphQL query:
{
user (id: 1) {
firstName
lastName
articles {
title
}
}
}
we will receive exactly what we need, nothing more, in a single query:
{
user {
firstName: "Amy",
lastName: "Sears",
articles: [
{
title: "Last night versioning saved my life",
},
{
title: "Webstorm vs Visual Studio Code vs Gedit",
}
]
}
}
Obviously with a data structure like this, and for those queries, it’s not a big improvement, but imagine our blog has gone far now, and on an article page, we show several informations about the author, the article itself, comments written about this article, informations about the author of the comment etc etc.
I can easily imagine this in GraphQL:
{
article (id: 1) {
author {
firstName
lastName
}
title
content
comments {
author {
firstName
lastName
}
textComment
createdAt
}
createdAt
}
}
I can ask for exactly what i need in a single query and avoid to chain queries and a heavy payload.
Glossary
- GraphQL : GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.
- API : An API (application programming interface) is a software interface allowing you to “connect” a software or a service to another software or service allowing them to exchange data and functionalities.
- REST : Representational state transfer (REST) is a software architectural style that was created to guide the design and development of the architecture for the World Wide Web.