For the past few years, GraphQL have risen in popularity it becomes hard for me to ignore now.
Now I've put some effort into learning GraphQL by making a simple app and here's what I found.
Problem Statement
What is it that GraphQL tries to solve?
In a typical REST API. Every endpoint is structured around ONE resource. This causes a common issue in Frontend (FE) development where upon encountering relationship between resource, the FE client have to fetch to multiple REST endpoints.
Also a REST endpoint usually expose all fields of a resource in the endpoint. Causing FE to sometimes, or most of the times, fetch unneeded data.
These are called overfetching. Sometimes we overfetch by calling multiple endpoints just to get the full picture of a resource. Sometimes we overfetch by getting unnecessary data presented by an endpoint.
A Look inside GraphQL Query
GraphQL introduce us to another layer of language to learn to. Let's take a look at this simple sample GQL
query {
products (price: "100,200") {
id
name
price
}
}
Very simple, and can be interpreted as:
SELECT id, name, price
FROM products
WHERE price between 100 and 200
Now GraphQL doesn't have a concept of separate endpoints per resource. Every request comes to a single root endpoint and all resources can be accessed by the query.
Let's have a case where we want to fetch every available discount to the product
query {
products (first: 10, price: "100,200") {
id
name
price
discounts {
rate
}
}
}
Again, very simple SQL equivalent would be
SELECT p.id, p.name, p.price, d.rate
FROM products p
LEFT JOIN discounts d
WHERE p.price between 100 and 200
LIMIT 10
Easy right? And orginally I thought that GraphQL can do this kind of optimization in the background. Except it turns out to be NOT TRUE at all.
Shifting Overfetching Around
In the previous scenario, what GraphQL does are
- Query the products and limit it to 10 results
- Foreach entry in products result, get the product available discounts.
This is called N+1 problem where basically we have to query N+1 times to database. Of which N equals to how many results in the previous step. In this case, we fetch 10 product once, and we query discounts at least once per product, equaling 10+1 separate query to database.
This makes me thinking. So is what GraphQL does, is just shifting around the overfetching problem away from frontend to backend and introduce another myriad of problems that does not exist in a typical REST API?
Is problem of Overfetching overstated by GraphQL enthusiast?
Dataloader
Now GraphQL have batching technique that might make nested query to become at least 1+1 instead of N+1.
The simplest implementation is to pool each id of the parent context into something that is called data loader. And after all the parent ids are collected, dataloader can do 1 batch query to database to get all the child.
But this again, adds another layer of problem. How do we attach the list of child results into its correct parent?
With dataloader, we have to return it into the same order as the parent. Giving us another layer of post processing.
Personal Take
Maybe it's just me but back before the GraphQL land and time, joining resource via code was (or still is? IDK) considered as hacky and might introduce unwanted bugs.
Seeing now that it becomes the norm with GraphQL kinda rubs me in the wrong way.
I haven't even talked about caching and mutation problem in GraphQL that doesn't exist in a typical REST API, yet. And the N+1 problem already gives me a bad impression about GraphQL.
For now at least I think GraphQL is more of a solution to a problem that I personally don't face.
Disclaimer
To other people who loves GraphQL and want to bash me in the head for this.
I am not trying to say GraphQL is bad for you. Just that it is not the right fit for me. At least for now.
Top comments (0)