GraphQL is great, it allows you to work in a declarative style by enabling you to select only the information or operations that you need.
However, just like any other tool, it’s not a silver bullet.
In this post, I’ll talk about five reasons you shouldn’t use GraphQL when the alternative is a REST architecture:
- REST can do much of what GraphQL does
- GraphQL will make some tasks more complex
- It’s easier to use a web cache with REST than with GraphQL
- You could have performance issues with GraphQL queries
- The way GraphQL schemas work could be a problem
Of course, these situations may not always apply to your project, but it’s important that you are aware of them and consider the implications.
REST can do a lot of what GraphQL does
GraphQL is an alternative to REST for developing APIs, not a replacement.
The main feature of GraphQL is to be able to send a query specifying only the information you need and get exactly that.
But you can also achieve this using REST, from passing the name of the fields you want to use in the URL (implementing the parsing and returning logic yourself):
And it is not difficult to implement. There are many JSON API libraries in many languages.
Do you want the benefits of using a schema and strong types in REST?
Use JSON schemas.
There are many libraries that implement and support this specification too.
Do you want to use a query language in REST APIs?
The point is that there are valid alternatives. Especially for small applications, where using GraphQL may be overkill.
Of course, there are situations where it will be complicated to implement these libraries and for those cases, it may be better to use GraphQL, which natively support all of these features.
But GraphQL can also make things more complicated.
GraphQL will make some tasks more complex
Using GraphQL in a simple application (for example, one that uses a few fields in the same way, every time) is not recommended because it adds more complexity because of things such as:
- High-order components
Which is not good from a maintenance perspective.
But even if the use of GraphQL is justified, there may be some complications.
Two examples are error handling and file uploading.
In REST, checking the response status is the only way to know if the request was executed successfully, if there was a server error, or if the resource was not found.
But in GraphQL, you get something similar to the following when an error occurs:
You will have to parse this message to know if there’s an error, and probably different errors will have slightly different formats or add some custom fields.
Some libraries, like Apollo client, help with handling errors, but not as easily as in a REST API.
About file uploading, this feature is not part of the GraphQL specification, so the implementation is left to you. Some options are:
- Use Base64 Encoding, which will make the request larger and expensive to encode/decode
- Use a separate server/API for this purpose
- Use a library like apollo-upload-server that implements the GraphQL multipart request specification
The third option is probably the most recommended. However, it means adding another dependency to manage your project and it may not be available for all programming languages.
It’s easier to use a web cache with REST than with GraphQL
I want to emphasize the web part, caching at the network level, because you can certainly implement a cache at the database level or at the client level with the in-memory cache implementation of Apollo Client.
Sick of debugging web apps? Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket pairs session replay with technical telemetry to quickly understand what went wrong.
But a cache implemented at the HTTP level (for example with a reverse proxy) that stores the content of a request can reduce the amount of traffic to a server or keep frequently accessed information in a location close to the client (like a content delivery network).
Since a REST API provides many endpoints, you can easily configure a web cache to match certain URL patterns, HTTP methods, or specific resources.
In GraphQL, there’s only one endpoint (most of the time an HTTP POST endpoint) where all the queries are sent. Since each query can be different, it is harder to use this type of caching.
This tool assigns identifiers to GraphQL queries producing a JSON file that maps queries and identifiers. With this map, the client only sends the identifier and the parameters of a query to the server so it can just look it up.
However, this adds another layer of complexity and it only partially solves the problem.
Performance issues with GraphQL queries
By being a query language for APIs, GraphQL gives clients the power to execute queries to get exactly what they need.
But what if a client sends a query asking for a lot of fields and resources? Something like “give me the information about the users that posted a review for all the books of this author”:
You can just let your users run any query they want. A GraphQL API must be carefully designed, it’s not just about putting it on top of a REST API or a database.
For complex queries, a REST API might be easier to design because you can have multiple endpoints for specific needs, and for each, you can fine-tune specific queries to retrieve the data in an efficient way.
This might be a bit controversial because multiple network calls can also take a lot of time, but if you are not careful, a few big queries can bring your server down to its knees.
In a GraphQL API, there are tools like Dataloader that allow you to batch and cache database calls, but in some cases, even this will not be enough and the only solution will be to block queries by calculating a maximum execution cost or query deep. And any of these solutions will depend on the library you’re using.
GraphQL schemas could be a problem
But schemas are static and the response the clients are going to get depends on the schema definition and the query they make.
For example, you cannot have more depth than what is specified in the schema or in the query, schemas that you can modify at runtime, or dynamic type definitions.
The GraphQL specification doesn’t cover dynamic features like these, so you have to rely on hacky solutions or custom server implementations.
On the other hand, I have seen people create very generic schemas to try to resolve more complex requirements:
This comes at the expense of most of the benefits GraphQL.
In these cases, it’s better to stick to REST.
GraphQL is a powerful tool, and there are many reasons to choose GraphQL over REST. But don’t forget to choose the right tool for the right job.
The points I have presented here may not always apply, but it is worth taking them into account to see if they can be addressed. There are still use cases where REST is a valid approach.
Plug: LogRocket, a DVR for web apps
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.