DEV Community

Jiri Spac
Jiri Spac

Posted on • Edited on

Overhead of using REST instead of Graphql with node.js

There are quite a few misconceptions when it comes to graphql. It cannot be cached on http protocol level, it has to return 200 code even when there are errors, it kills fluffy kitten every time you make a mutation.
In this short post I would like to address one of them in particular. No not the one about the kittens.




Let's analyse and dissect what these developers might be talking about.

Overhead on the Client side

As a consumer of graphql APIs you need to send an exact list of fields you want back. If your model is complex and it has lots of fields, this does indeed introduce extra DX complexity writing the API request.
This "overhead" only exists without tooling.
Every graphql API should come with graphiql/playground bundled. These tools complete the query for you, so there is little to no developer time lost. On the contrary developers can explore the API at the same time as they query.

Even when it doesn't come bundled with the API, developer can run a variety of graphql clients on their end.
For example graphiql does it here.
Hence I came to a conclusion that it's not this overhead that these people are talking about.This is too trivial and solvable with tooling everyone uses by default. This cannot be it.

Overhead on the Server side

This one is harder to crack. Is this actually a myth? There are myriad ways to write a backend in both of these. In order to prove I knew I had to get my hands dirty.

I was always a fan of DRY, not DRY nazi, just a fan. So I've been actually always searching for less verbose ways to write APIs, ever since I started years ago.

REST

In the last few years I've gravitated toward stacks centered around fastify. So let that be the http server base for our comparison.
I don't think there are more succint ways to write a documented REST api other than fastify and fastify-swagger. The way fastify-swagger leverages validation schema to produce the docs is quite awesome. It reminds me of a a poor man's thing which starts with a capital "G" and it's killing kittens.

Graphql

Similarly, for the Graphql camp, I don't know anything less verbose than Typegraphql and mercurius.
Mercurius-fastify plugin has the best defaults of any GQL server and performance on whole different level compared to apollo-server.

So I've taken a bit of time today and written a single CRUD endpoint for a very simple blog. There is no authentication, no rate limiting, no caching, nothing extra-just a pure bussines logic for CRUD over one DB table.
What I do implement in both is validation and documentation as we need to have feature parity for a fair comparison.
For ORM I chose prisma, as it offers awesome generators to spare my lazy ass from writing API schemas manually.
For the DB we just use sqlite.

What was the result?
🥁
See this repo: https://github.com/capaj/node-rest-vs-graphql

These endpoints are implemented:

  • query for blogpost with filtering by from and to dates
  • query to fetch a single blogpost
  • mutation to create a new post, update existing one and delete a blogpost

PR stats

Just for this very simple API, REST adds 21 extra lines.

I would welcome any PR regarding simplification of the REST api, because I may have missed something. Maybe there is some magical way how to have validation and documentation without all that work. Maybe I just haven't learned it yet. I am just a junior dev 4life.

I really wish there was an easier way to properly do REST apis in node.js. Personally I'll be sticking to typegraphql and mercurius.
Keep in mind that for a more complex api-where you have deeply nested relations of entities, REST becomes even more unwieldy. Graphql is natural for representing data with lots of relations allowing the consumer to nest their queries deep. In leaf resolvers you always have access to a parent when resolving a child-you can often use this to simplify your BE code.
These practices of structuring endpoints exist in REST as well, but it's all manual. You actually need to write bunch of middleware to get it to work.

One last reason for me to avoid REST is that I am quite bad at remembering to do something when I am not forced to do so by an automated system. If I was writing REST apis, I would most likely need a colleague to remind me to add that optional validation in every odd code review. This is potentially solvable in fastify type definitions. I think it's not likely it will ever get implemented. Fastify is primarily a javascript framework and the type defs are manually added just for consumers.

Final note: please if you see anyone on twitter talk about how Graphql has implementation overhead compared to REST, do send them this link: https://github.com/capaj/node-rest-vs-graphql/pull/1

Top comments (2)

Collapse
 
edgar0011 profile image
Martin Weiser

"Sure, with graphql you need to send an exact list of fields you want back." Not true, depends on how resolvers are implemented, you can have some default set of fields which you dont have to ask for every request of particular entity.

Collapse
 
capaj profile image
Jiri Spac

Interesting. Haven't seen this in the wild.
You certainly can make some resolver return JSON scalar and in that case you cannot even pick the fields, but I only use that for data of unknown shape.