As part of our interview grid, we have a list of questions we to ask every candidate.
One of these questions is “Have you used GraphQL before?”, followed by “What do you think are the advantages compared to REST?“.
Nothing very unusual so far.
But hearing so many different answers did highlight that there is an interesting discrepancy between the advertised benefits of GraphQL, and some of the actual “real-life” benefits that people remember.
This post is an overview of some unspoken yet real advantages of using the new query language based on our own team’s experience and the experience of dozens of interviewees!
Developers who vaguely heard about GraphQL usually share the same typical opinion.
Common answer #1 GraphQL lets developers request only the fields the [frontend] application needs. It saves bandwidth and makes the code cleaner without having to fetch all the unused fields and properties.
✅ This answer is correct. Receiving cleaner response is even one of the main points advertised on the GraphQL website (“Ask for what you need, get exactly that”).
Reducing the bandwidth usage is also true to some extent, especially if using GraphQL can transform what would be 10 different requests into a single one at the start of your application. But arguably, it has a smaller impact overall.
Another answer is:
Common answer #2 GraphQL lets you manage a single endpoint.
✅ Also technically correct. Maybe a bit underwhelming on its own when you do not consider the whole picture here.
If so many great companies are adopting GraphQL, it is first and foremost for its philosophy and design. Having a single endpoint is only a consequence of it. The real benefits precede it.
Let’s explore some of them.
Typically, a steep learning curve is not considered a “pro”. It would more likely be a “con”.
Yet, in this case, looking back, having our team approach a whole new paradigm was very beneficial.
- ✨ It creates excitement. Learning something new is at its core what motivates every engineer. And GraphQL definitely is a new exciting thing to learn. Surely sometimes it causes some headaches, but undeniably generates a lot of excitement.
- ⚙️ It forces everyone to “rethink” the basics. At this point, we are all used to REST. And we do not spend the effort to “explain” it anymore. We all expect REST to be a certain way and we all have different experiences with it. “Should it return 404 or 401?”, “Should it be
accounts/v2?“. Everyone already has a pre-made response. With GraphQL instead, everybody is learning from scratch and everything should be carefully and consciously designed from the basics. From authentication to error code handling, the whole team can start a discussion with a fresh and open mind, striving for good practices.
Speaking of good practices, GraphQL specifications are documented here: https://spec.graphql.org/.
That’s it. A clearly defined reference of what a proper implementation should look like.
This is a very solid and modern foundation for anyone trying to build a new API model.
Furthermore, the team at GraphQL learned from REST and has a couple of improvements built in. Like pagination.
Pagination is always way harder than it seems. There are many limitations from the most common pagination implementation, as perfectly described by this article.
GraphQL has a recipe for “cursor-based” pagination (technically from the Relay specifications, and not directly the GraphQL) which is extremely powerful: https://relay.dev/graphql/connections.htm.
If you are using a “popular” GraphQL client on the frontend, there is also a chance that this powerful pagination mechanism is already baked inside the tool (Apollo has “relay-style” pagination already implemented https://www.apollographql.com/docs/react/pagination/cursor-based/#relay-style-cursor-pagination) which will save a lot of engineering resources to your team.
An unhealthy backend-frontend relationship is often caused by inconsistencies.
Everyone hates it when:
- 💩 A
Userobject has different properties when returned from different endpoints.
- 💩 A date is randomly returned as
YYYY-MM-DDor as a
- 💩 Data “received” needs to be refactored before being sent again to another module which expects a slightly different format.
Also, a good practice is usually to define models locally in the frontend parts, which comes with several pain points:
- 👎 Systematically redeclaring local models for API responses, which might differ or not from backend models
- 👎 Transforming all incoming data (e.g. snake case to camel case) and transforming it back for outgoing data.
- 👎 Having different local models on different frontend applications (mobile, web…)
GraphQL has a schema-first philosophy by design. Everyone from backend to frontend should in theory always be talking about the same
User object (even if we all know theory can be very different in practice). The requests expected inputs and outputs are always clearly defined by design.
Having a shared foundation for talking about data models also enforces a broader way of thinking. In our team, we are seeing way more constructive discussions about mutation and query design with GraphQL than discussions about REST endpoint design.
With GraphQL, it just feels like “the frontend and backend are closer”.
On the client, the simple effort of consciously having to define the queries and mutations (selecting which fields to request) enables a whole mindset. It feels natural to “move” some logic to the backend if necessary (and vice versa).
On the backend, it becomes more straightforward to build a mental model of how the frontend will use the queries and mutations. Queries, because they feel declarative, better represent a single UI view. Similarly, mutations represent user actions but also have to return something, usually the entity that has been modified. It forces the backend to anticipate how clients will update their own local database, which at the end of day are simply partial local representation of the entire data graph.
GraphQL is built with code generation in mind.
Admittedly, “codegen” is not a GraphQL feature. It is perfectly possible to use Swagger or similar tools to generate client code for REST API.
Yet, the current community and ecosystem make it really easy to start building a GraphQL API with code generation in mind (see https://www.graphql-code-generator.com/, https://github.com/apollographql/apollo-tooling).
Code generation is a powerful automation flow. It removes some frictions between languages and platforms.
With GraphQL, there is one source of truth: the schema. All platforms then. have their own “implementation” of the schema. But everyone always expects the same operation, the same entities, the same enums, etc.
The industry is moving towards tools and stacks that tend to provide documentation “by design”.
These days, teams do not deploy apps and websites the same we used to do it just a couple of years ago. Instead of manual migrations and procedures, we prefer to have “in-code” configuration for our infrastructure and deployment flows. As nicely described on puppet website:
Infrastructure-as-code Puppet is built on the concept of infrastructure-as-code, which is the practice of treating infrastructure as if it were code. This concept is the foundation of DevOps — the practice of combining software development and operations. Treating infrastructure as code means that system administrators adopt practices that are traditionally associated with software developers, such as version control, peer review, automated testing, and continuous delivery. These practices that test code are effectively testing your infrastructure. When you get further along in your automation journey, you can choose to write your own unit and acceptance tests — these validate that your code, your infrastructure changes, do as you expect.
Our team uses Altair that automatically creates a documented playground that updates in real time. On every backend deployment, the extension will update its documentation:
It lists all the operations, with the expected inputs and outputs. It even supports directives (like
@DEPRECATED) to always make sure everyone is on the same page!
GraphQL is still “new” (Stable release is from June 2018) compared to a well-established architecture like REST. But it seems pretty clear that its adoption is rapid. It is definitely refreshing from a technical perspective to have a different paradigm for designing and playing with API endpoints.
Beyond that, I am very enthusiastic about the transformation in teamwork and collaboration. To me, GraphQL opens a whole new mindset for developers to juggle between frontend and backend. If executed properly, it can definitely make teams work together more effectively.