REST vs GraphQL for an API
The goal here is to help you think about and consider the costs and benefits of building a REST vs GraphQL API for your next project. Technology decisions often include thinking about the trade-offs. Hopefully this can help you evaluate these two technologies and approaches.
You have experience writing and using REST APIs. You’ve heard of GraphQL and some of the benefits it can bring. A new project is starting and you can choose which technology to use for the API. How do you decide which to do? What things should you consider?
A RESTful API is centered around “resources” and operates using “verbs”. The most common verbs are GET, POST, PUT, PATCH, and DELETE. The success or failure of a request is communicated through standardized HTTP response codes like 200, 201, 204, 404, 422, etc.
You can read more about RESTful APIs here: https://restfulapi.net/
REST APIs in Elixir are implemented using standard Phoenix Controllers.
“Resources” are supported by the Router.
GraphQL allow developers to define a “schema” that describes the structure of the data. You can “query” data and make changes (inserts, updates and deletes) using “mutations”.
To appreciate the value of GraphQL, it helps to understand one of the main problems it was created to solve.
Netflix creates the “Netflix” apps that are embedded and installed on devices and even pre-installed in Smart TVs. Imagine the Netflix app is installed in a Panasonic Smart TV but you know that the TVs firmware will never be updated. If you want to keep that app working, you need a way for the client and server to communicate that is resilient to server version changes.
Facebook creates iOS and Android applications so users can interact with the services and their “feeds”. People continue using their phones long after the provider (Apple, Samsung, Google, etc) officially ends support. Facebook makes money by keeping people engaged in the system and selling Ads. Facebook doesn’t want to maintain multiple versions of their app that target multiple versions of iOS. It would be enough that the old version the user installed on their phone just keeps working and doesn’t break when new server releases and features role out.
Both Netflix and Facebook faced this similar problem. A problem of supporting client applications that will never be updated but also not wanting to mire down the server (and forward progress) by maintaining many API versions. To address this, Netflix created Falcor and Facebook created GraphQL.
Of these two technologies, GraphQL seems to have won in both public opinion and adoption. Even Netflix (at least the Marketing department) has been adopting GraphQL too.
GraphQL solves other problems as well. A more elegant solution to versioning is a significant one, but not the only one.
You can read more about GraphQL APIs here: https://graphql.org/
GraphQL APIs in Elixir are implemented using the Absinthe library.
REST Pros and Cons
- Familiarity: You are familiar and comfortable with the technology and approach.
- API Client Acceptance: Customers/Integrators are likely familiar with and comfortable making REST API requests.
- Caching: How you solve caching is a well understood solution.
- Learning Resources: Because REST has been around for so long, there are lots of examples and resources available.
- Documentation: A REST API is not discoverable by the tooling. You need to provide separate API documentation. There are a number of available solutions, but those exist outside of the REST tooling.
- Version Management: Adding new fields may not break client compatibility. However, extra data is now being computed by the server, sent of the wire to the client, and the client throws may not actually use it.
- Payload: Data responses often include “everything the client may need”. The data payloads are often larger than what is actually needed for a specific client and it’s immediate request needs.
- Deprecation tracking: There is no way for the server to know what data the client is using or throwing away from the response. Developers can’t tell when a data field is safe to remove.
GraphQL Pros and Cons
- Version Management: GraphQL was created to specifically address this problem.
- Payload: Clients request only the data they needed. Payload sizes are much smaller and focused. This also impacts data transportation costs and time.
- More efficient aggregation: Do you need to aggregate data to answer a request? This could be making requests to additional services and aggregating the results. It could be performing expensive operations to compute a response. Because the client requests only the data it will use, this means expensive operations on the server can be skipped when the client doesn’t want that particular result. This is helpful for API requests that aggregate data. A REST request doesn’t communicate what will be used by the client so expensive computations are still performed and potentially discarded.
- Documentation: GraphQL schemas, queries and mutations are self-described by the tooling. This makes a GraphQL API much easier to discover and work with. Tools like GraphiQL are
- Deprecation tracking: Because a client requests only the data it needs, using Telemetry or other tracking methods on the server, developers can more easily determine which fields are no long used and can be safely removed.
- Tooling: GraphiQL is a powerful development tool created and supported by the community. GraphiQL support is built-in to Absinthe making it easy to support in your Elixir project.
- Unfamiliar: Requires learning new technology and terminology.
- Pagination: There is no formalized approach to handling list pagination. The same can be said for REST as well. However, a stricter GraphQL structure called Relay offers a ready solution. Using Relay also requires adopting more of the project’s design decisions for how the response data is structured. The point is, there are multiple options but not an obvious, “do it this way” solution. An good-fit pagination solution may require additional research for your team.
- Caching: Caching for performance is still available, however the developer has to think about it and do some extra work. Caching around REST is more straightforward and understood.
- API Client Acceptance: Customers/Clients may not be comfortable being provided with a GraphQL API. REST may be more familiar to them. Additional client training, hand-holding or writing a REST wrapper* may be required.
*REST wrapper: An application can provide a REST interface wrapper. This just means creating Phoenix controllers that answer REST requests and transform the request into a GraphQL request. This keeps all the business logic in one place and ensures a single request/response path.
Given the above scenario, I recommend that if your timeline allows for learning a new technology, then using GraphQL can have a multiplying effect for your project. GraphQL has continued to mature as a solution and the Absinthe library has matured and improved as well.
Bonus Tip: Avoiding N+1 queries
When adopting a new technology, I always encounter issues I didn’t anticipate. Allow for that and expect it. Here’s another tip to save you time so you can plan for it.
When using REST, to avoid N+1 queries you may query the data using a multi-table join to pull the data together. While straightforward, it can be inefficient when a client doesn’t use whole sections of the joined data. In GraphQL, an Absinthe tool called DataLoader was created to more efficiently solve this. While this supports more optimized queries, it is also something new to learn.
Great fit for…
GraphQL makes a lot of sense for the following situations:
- Mobile applications: Android and iOS versions may diverge or you may need to simultaneously support multiple versions of the client.
- Embedded systems: where an Elixir application is makes requests for data.
Want help with your specific situation?
Let's chat to see how I can help you!
Want to go deeper on your own?
I had a conversation with Ben Wilson on the podcast about this topic. If you would like to dig deeper and hear more, you can find that episode here.
Podcast episode with Ben Wilson.
Leave a Comment
You must be logged in to post a comment.
From my experience (a lot of using GraphQL in ways in my opinion it’s not the best tool for the job) a couple more things to consider before choosing GraphQL over REST or other simpler APIs:
1. Increased overhead with GraphQL. When your GraphQL server gets a request, it has to parse the request, figure out what data the client wants, and cobble everything together. A more traditional API routes the request to a controller written to handle specifically that request. The GraphQL overhead is usually negligible, but I’ve worked on a high-performance app where response times were cut in half moving off of GraphQL (1.3ms vs 2.5ms).
2. Potential for unnecessary complexity with GraphQL. I’ve added several queries to GraphQL APIs that were very purpose-built. I knew exactly who was going to use them and which fields were going to be asked for in the response. It would have been simple to create new routes/controllers, return exactly what was needed, and move on. Instead they became fields on existing types. Queries that were only meant to be run for one resource at a time had to be protected from N+1 if someone requested the field on a list of resources. Queries that could have taken a list of IDs had to instead go through the batch resolution cycle. Sure, a lot of that could be poor API design choices, but my point is that you don’t need the complexity of GraphQL if you know exactly how your API is going to get used.
Great insights! Thank you for sharing!
I went through the same problem of unnecessary complexity and a little slowness.