Playing with GraphQL
Tags: graphql
Published: 2021-02-20 05:01:23

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

```graphql
query  {
  products (price: "100,200") {
    id
    name
    price
  }
}
```

Very simple, and can be interpreted as:
```sql
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

```graphql
query {
  products (first: 10, price: "100,200") {
    id
    name
    price
    discounts {
      rate
    }
  }
} 
```

Again, very simple SQL equivalent would be

```sql
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

1. Query the products and limit it to 10 results
2. 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.