GraphQL is a new technology and it completely brought in new ideas on how to communicate better between client and server. The benefits, when compared to REST APIs, are fewer network requests, colocate data requirements, better tooling and documentation like strict typing, automatic update of documentation when the schemas are changed, etc.., Though it brought in multiple benefits, it does suffer from certain issues. One of the issues that I am going to explain in this post is the normalizing of responses. For example, let's say there are 5 people in a social network and they are pretty close and have a lot of mutual friends in common. So a typical to fetch the person's details and their friend's details using graphql query would be like something as shown below,
Now inspecting the response returned by the graphql endpoint, we notice that there a lot of 'Friend' responses repeated because as said, they have a lot of mutual friends. The size of the response is around 350 KB in size and it is quite a lot. There is no such idiomatic way to reduce the size of the response in this scenario. Now let's rewind back and see, what it would be the case in the REST API scenario. In REST API world, there are lots of established response formats like JSON:API, HAL, ODATA, etc.., In case of JSON:API, it does have a solution to these kinds of problems by normalizing the response into grouped entities to reduce the size of the response. It does so by grouping into entities and adds a relationship to the entity as a reference in each repeated place. After reading a few blog posts, I arrived with this solution by using the gajus's GraphQL Deduplicator library to deflate and inflate responses to bring down the size.
- No need to change a single line of code in the backend server for this experiment.
- In the case of frontend, just a piece of code to the service worker to inflate the responses.
- It helps to quickly prototype to check if it brings any new performance benefits or not.
This place acts as an interceptor between your client and server communication so we use the
graphql-deduplicator library to deflate responses return by the graphql endpoint. We do a bunch of checks to make sure it is the graphql endpoint URL and we deflate the responses obtained from the upstream server and then, we send a newly constructed response to the client. To see a demo of how the deflated response looks like,
You can visit https://graphql-compressor.asvny.now.sh/ and click 'Fetch Deflated' button'.
As you scroll down, you can notice that some 'Friend' responses have only __typename and id because the response was normalized and these two attributes act a reference to the resource. The original content can be seen only once in the deflated response.
Since, GraphQL is generally a "What you see, is what you get", we have to inflate the response returned by the Cloudflare worker back to its original form to avoid errors. The same checks are done again to know that we are intercepting the correct graphQL endpoint and then we inflate to its original form.
You can visit https://graphql-compressor.asvny.now.sh/ and click 'Fetch Normal' button'.
For a sample of 5 persons with 20-25 mutual friends, the original response was 280-320 KB in size and after introducing the above technique, we can notice an unbelievable decrease in size and the size was around 70-90 KB. All the sizes that I have mentioned are actually uncompressed sizes if we are talking with
br encoding then the difference was very marginal. With encoding, the difference was around 0.5 KB to 2 KB.
To see the full code, here is the github repo link.
Thank you, reader!