Pros and Cons of GraphQL

REST has been around for almost 20 years ( https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf was published in 2000) and has been the dominant paradigm for HTTP APIs since the XML-RPC stone ages. ThoughtWork’s Tech Radar has had `RESTful techniques` in `adopt` state since 2010 ( https://www.thoughtworks.com/radar/techniques/web-as-platform ). The community has even built advanced specifications on top of REST, for example JSON API ( http://jsonapi.org/ ). It is safe to say that REST is robust, reliable, and a good choice for many APIs.

In comparison, GraphQL has a lot to prove. On the plus side,

  • network performance improvements
  • loose coupling between client and server
  • strong typing
  • developer tooling

Users should get faster app experiences by way of GraphQL. The big speed gain is in aggregating multiple HTTP requests into one. Each HTTP request suffers from latency, especially on mobile data networks. Making many requests results in users waiting, waiting, waiting.

This works because GraphQL is a flexible query language for APIs. It allows developers to get exactly the data they need.

For example, say that we wanted the most recent guest reviews from the last few hotels booked by a user*. Typically, we would call the /user/{id}/reservation endpoint for a list of their reservations and then call another endpoint, maybe /property/{id}/reviews, to get the most recent guest reviews. If the user had 10 recent trips, this would be 11 requests (https://www.infoq.com/articles/N-Plus-1). With GraphQL, a developer can compose the request for recent bookings with a nested request for recent guest reviews. Then they POST to an endpoint and that’s it.

This mechanism promotes loose coupling. Enhancing a mobile app experience does not require a new API, if the data is available then app developers can simply modify their queries. Old app releases continue to retrieve their data as before.

Strong typing prevents a few of my favorite reoccurring API bugs. No longer will users in Norway suffer because mobile operating systems use locales (nb_NO and nn_NO) different to those on servers (no_NO). The locale type is enforced by a schema. No longer will a server send a String in place of an Int; types in responses are also validated against the schema.

GraphQL offers even more goodies for developers. A few pretty query tools are out there. A quick demo of GraphiQL, GraphQL Playground, or GraphQL Voyager will warm the soul of even the most hard-boiled developer. The promise of schema-stitching suggests we can compose lower level GraphQL services into a GraphQL edge API with minimal additional effort.

If we remove the rose-colored glasses and disable the reality distortion field, then some tradeoffs become apparent.

  • kiss HTTP caching goodbye, everything is POST
  • GraphQL has some aspects of earlier Facebook tech that did not go so well, see FQL
  • Will GraphQL servers become big and bloated? Without engineering discipline, it feels likely
  • Are we becoming too dependent on the Apollo client? Alternatives exist, including plain old POST, but Apollo has momentum and developer mindshare

The elegance of REST is in how it works with the architecture of HTTP. Preeminently, REST leverages all the caches. Whether the cache is on a network router, within an HTTP library, or on the webserver — a GET request might benefit from another recent request. ETAG and `Last-Modified` headers enable fine grained control of caching (https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching ).

As per the HTTP specification, POST requests are not supposed to be cached. There is some ambiguity with regards to 303 response codes ( https://en.wikipedia.org/wiki/HTTP_303 ) but traditionally POST requests are not idempotent, thus not suitable for caching. Most of today’s internet won’t consider caching a POST request.

Orginally, all GraphQL requests were POSTs. The philosophy of GraphQL encourages caching locally but developers mostly rely on their GraphQL clients to do the hard work of cache invalidation and memory management.

Some GraphQL patterns enable requests over GET (persisted queries) and with other gymnastics also permit cacheing (https://blog.apollographql.com/caching-graphql-results-in-your-cdn-54299832b8e2 ). While it is possible the make a GraphQL API cachable, it tightly couples the client to the server and requires another level of tooling.

Moreover, tomorrow’s CDNs may be better positioned to cache GraphQL. The idea of “Lambdas at the Edge”, ie serverless functions in CDNs, offers the hope of intelligently cacheing the requests made by your GraphQL edge server (https://travislsmith.com/caching-problems-with-graphql-at-the-edge/ ).

Facebook introduced GraphQL at their Reactjs conference in 2015. A year later they closed down their FQL services (https://developers.facebook.com/docs/reference/fql/ ). FQL could also be described as a `flexible query language for APIs` yet it was ultimately shut down. (To be clear, GraphQL is an open specification and Facebook couldn’t shut it down even if it wanted to.) The launch of Graph API, which replaced FQL at Facebook, was lauded as better aligned with standard web development and scalable to all the items in Facebook’s graph. Facebook’s Graph API follows many REST principles. Does GraphQL marry the best of FQL and REST? Or will GraphQL, over time, again reveal the limitations of working against the grain of the web?

On the face of it, a single API that consolidates all the external facing data sources in your organization sounds convenient. However, it also sounds like a monolith and flies in the face of today’s development best practices. Schema stitching (https://www.prisma.io/blog/graphql-schema-stitching-explained-schema-delegation-4c6caf468405/ ) offers a clean alternative but also supposes that someone will front all your data sources with GraphQL.

Two aspects of GraphQL are especially concerning from a long-term perspective: no versioning and partially complete requests. While the GraphQL evangelists tell us that we will not need versioned endpoints, we can just stop requesting some parts of the schema, this is easier said than done. Anyone who has maintained an API knows that clients (and customers) don’t always update. God forbid we have a big cleanup in our data models!

A GraphQL request could partially complete, this goes for queries or mutations. Our clients need to account for this; the beauty of a single API starts to fade into lots of error checking. More than likely, partial failures are a leaky abstraction and start to reveal some of the interdependencies that were meant to be hidden away behind that single API.

Finally, almost any web search on GraphQL will yield some hits mentioning Apollo (https://www.apollographql.com/ ). The developers of Meteor have jumped (somersaulted) into the GraphQL bandwagon and offer the most powerful GraphQL clients for Android, iOS, and web development. It would be hard to suggest using anything but the Apollo clients, especially because they address the difficult issues of local caching and support advanced features like subscriptions (https://graphql.org/blog/subscriptions-in-graphql-and-relay/). Is this too much of a good thing? Will there soon be Apollo developers, in the same way that there used to be jQuery developers? Is this a space where we can afford a monoculture?

Should you use GraphQL? It depends.

* Why you ask? Perhaps we want to encourage a user to leave a guest review by showing recent ones