Editor’s note: This GraphQL and REST API comparison post was last updated by Emmanuel John on 2 October 2024.
GraphQL and REST are the two most popular architectures for API development and integration, facilitating data transmissions between clients and servers. Comparing them is necessary for determining the right approach for specific API scenarios because both offer advantages for different use cases.
The biggest difference between GraphQL and REST is how data is sent to the client. In a REST architecture, the client makes HTTP requests to different endpoints, and the data is sent as an HTTP response, while in GraphQL, the client requests data with queries to a single endpoint.
It’s also worth noting that, in REST, the structure of the response object is defined on the server. In GraphL, you define the object on the client.
By evaluating both, you can decide which approach best fits your project’s needs regarding data fetching efficiency, API flexibility, error handling, real-time support, ease of implementation, integration, and maintenance.
Here’s a table summarizing the main features of REST and GraphQL for easy comparison:
Feature | REST | GraphQL |
---|---|---|
Data over-fetching/under-fetching | Fetches more or less data than needed by the client | Fetches precise fields requested by the client |
Schema definition | Has no strict schema enforced by default | Uses Schema Definition Language to enforce strongly typed schema |
Caching | Easy network-level caching using the standard caching mechanism | Difficult to use the standard caching mechanism at the network level due to a single endpoint |
Error handling | Uses HTTP status codes for error handling | Returns 200 OK for all requests, along with the error property in the response object |
API structure | Has multiple endpoints based on the amount of resources | Has a single endpoint for all queries/mutations |
Real-time communication | No native support for real-time communication. It requires extra protocols like WebSockets or Server-Sent Events | Native support for real-time client-server communication via GraphQL subscriptions |
GraphQL simplifies aggregating data from multiple sources or APIs and then resolving the data to the client in a single API call. On the other hand, API technologies like REST would require multiple HTTP calls to access data from multiple sources.
Here, I want to emphasize network-level caching because you can implement a cache at the database level or the client level with the in-memory cache implementation of Apollo Client.
For example, let’s say you have a cache implemented at the HTTP level with a reverse proxy that stores the content of a request. This 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.
Because a REST API provides many endpoints, you can easily configure a web cache to match certain URL patterns, HTTP methods, or specific resources. Also, the HTTP GET method is naturally cacheable by browsers, proxies, and CDNs.
In GraphQL, there’s only one endpoint, usually an HTTP POST endpoint, where all the queries are sent. This complicates caching because the query itself is in the request body, and reverse proxies and CDNs often cache based on URL and headers so it’s harder to use the standard caching mechanism at the network level. To reduce the amount of traffic to the web server, you can use persisted queries with PersistGraphQL. Keep in mind that at the time of writing, this tool is no longer maintained, but it still works.
PersistGraphQL 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.
GraphQL ships with built-in type safety in its schema. Each field in the schema is typed, ensuring that clients know the exact structure and type of the data they will receive. This reduces runtime errors in client-side applications.
REST doesn’t inherently provide type definitions, making it prone to runtime errors in client-side applications.
GraphQL is an excellent solution to the unique problem of API flexibility and efficiency around building and consuming APIs, particularly when dealing with large datasets. When used as designed, GraphQL can be an ideal tool due to the following features.
GraphQL was designed to allow the client to ask for only the data it needs. While the server might be able to deliver more data to the client for a single request, it would only send the data that the client requests.
If you want the client to control the type and amount of data it needs, GraphQL is ideal for your project.
Bandwidth is a problem for small devices like mobile phones, smartwatches, and IoT devices that can’t handle large amounts of data.
Using GraphQL helps minimize this issue. Because GraphQL allows the client to specify what data it needs, the server doesn’t send excess data, which can reduce the app’s performance when bandwidth is limited.
GraphQL exposes a single endpoint that allows you to access multiple resources. In addition, resources are not exposed according to the views that you have inside your app. For example, if your UI changes, and requires either more or less data, it won’t have an impact or require changes from the server.
If your application data model changes frequently due to fields being added or removed, or the relationships between resources are complex, GraphQL would give you greater flexibility in adapting to these changes compared to REST. Its dynamic schema, along with introspection and dynamic queries, make it a better fit for such use cases. REST, on the other hand, would require more updates across multiple endpoints and wouldn’t provide the same granularity in fetching data.
By allowing you to define a schema, GraphQL offers many benefits, such as automatic validation and introspection. Depending on how you write or generate your schemas, static schemas could become a problem when you have a changing data model because the response the clients get depends on the schema definition and the query they make.
The depth of structures is confined to the limits set by the schema or query, but schemas can be adjusted during runtime, and dynamic type definitions are possible. You can solve this problem in GraphQL by building schemas programmatically using a code-first approach. The design process begins with coding the resolvers, and the SDL version of the GraphQL schema is generated programmatically.
Now that we’ve outlined several GraphQL use cases, let’s explore why you might prefer REST in certain situations and review some key tips to help you decide when to use each.
As 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 many fields and resources?
Take the following example, where the query is requesting information about users that posted a review for all the books by a certain author:
author(id: '1234') { id name books { id title reviews { text date user { id name } } } }
With GraphQL, users can’t simply 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 establish multiple endpoints for specific needs, and you can fine-tune specific queries to efficiently retrieve the data.
This might be a bit controversial because multiple network calls can still take a lot of time. But if you’re not careful, a few big queries can bring your server down dramatically. In that sense, GraphQL’s greatest strength can also be its greatest weakness.
In a GraphQL API, tools like Dataloader allow you to batch and cache database calls. But in some cases, even this isn’t enough, and the only solution is to block queries by calculating a maximum execution cost or query depth.
Libraries like graphql-query-complexity help limit the size and complexity of queries to prevent performance issues and protect your GraphQL servers against resource exhaustion and DoS attacks. graphql-query-complexity rejects complex queries before they can affect your server’s resources:
const { ApolloServer } = require('apollo-server'); const { getComplexity, simpleEstimator } = require('graphql-query-complexity'); const server = new ApolloServer({ typeDefs, resolvers, plugins: [ { requestDidStart: () => ({ didResolveOperation({ request, document }) { const complexity = getComplexity({ schema: server.schema, query: document, variables: request.variables, estimators: [simpleEstimator({ defaultComplexity: 1 })], }); if (complexity > 100) { throw new Error('Query too complex!'); } }, }), }, ], }); server.listen();
The above code estimates the complexity of a query and rejects those exceeding a defined threshold of 100, preventing potential performance issues.
It’s important to keep in mind that GraphQL is an alternative to REST for developing APIs, not a replacement.
The main benefit of using GraphQL is the ability to send a query that specifies only the information you need and receive exactly that. However, you can achieve this same effect using REST by passing the name of the fields you want to use in the URL, and then implementing the logic for parsing and returning the data yourself:
GET /books/1492030716?fields=title,pageCount
Although this looks easier to implement, the downside is that every REST endpoint would need custom logic to parse and filter the fields, which adds complexity when handling nested data, which is easier to achieve with GraphQL.
Thankfully, the JSON Schema helps define the structure of your API responses, enabling validation and consistency, and is available in many languages. If you want the benefit of using a schema and strong types in REST, you can use JSON schemas; many libraries implement and support JSON schemas. However, JSON Schema lacks the introspection and real-time flexibility that GraphQL offers.
If you want to use a query language in REST APIs, a solution like OData is a great alternative. OData, short for Open Data Protocol, was originally developed by Microsoft in 2007. It is an open protocol that enables you to create and consume queryable and interoperable RESTful APIs in a simple, standard way. OData gives you a rich set of querying capabilities and is quickly gaining ground for its open source approach and scalability.
There are many valid alternatives, especially for small applications and projects where using GraphQL might be overkill. By the same token, you’ll run into situations where it would be complicated to implement these libraries and easier to use GraphQL, which natively supports all of these features. However, GraphQL can also complicate things, which we’ll discuss next.
Using GraphQL in a simple application is not recommended. For example, in an application that uses a few fields the same way each time, using GraphQL adds more complexity because of things like:
From a maintenance perspective, this is especially detrimental because you need to update the schema with every new change introduced in the backend and also maintain resolvers for each query and mutation. But even if using GraphQL is justified, there may be some complications. Two examples include error handling and file uploading.
In REST, checking the response status is the only way to know whether the request was successfully executed, if there was a server error, or if the resource was not found. But when an error occurs in GraphQL, you get something similar to the following:
{ "data": null, "errors": [ { "message": "Validation error...", "locations": [ { "line": 5, "column": 6 } ] } ] }
You’ll have to parse this message to know if there’s an error, and different errors will probably have slightly different formats or some custom fields.
Some libraries, like Apollo Client, help with handling errors, but it’s not as easy as in a REST API.
File uploading is not part of the GraphQL specification, so the implementation is left to you. Some options include using:
The third option is probably the best. However, it means adding another dependency to manage your project, and it may not be available for all programming languages.
Error handling in REST is easier than in GraphQL. RESTful APIs follow the HTTP specification regarding resources and provide different HTTP status codes to indicate the state of API requests.
Meanwhile, GraphQL returns the 200 Ok
status for every API request, including for errors. This makes it difficult to manage errors and makes it hard to integrate with monitoring tools. Although the Apollo client library normalizes errors with built-in mechanisms to distinguish between HTTP status errors and GraphQL-specific errors, making the process easier, it still doesn’t address the challenges with monitoring tools.
Introspection is the ability for clients to dynamically query the schema and receive detailed information, including its types and activities.
Attackers can execute precise attacks and access unauthorized information caused by exposing private data related to the underlying data model. Some mitigation techniques disable introspection in production, implement rate limiting, and use field-level authorization to block access to sensitive schema parts.
Rate limiting in GraphQL helps to restrict the number of operations in a certain amount of time, which prevents abuse and protects against denial-of-service attacks. When there is no efficient rate limitation, attackers can send numerous API requests to overwhelm the server and cause API spam and service depletion or unavailability.
Query depth is the number of nested fields in a single query that shows how deeply a client can explore the data graph. Security challenges can arise when clients send very deep or nested queries, which can cause resource depletion and server performance downtime.
Complex nested queries can be created by an attacker, resulting in denial-of-service issues. We can easily prevent malicious use of the query depth feature by limiting the maximum depth of any incoming queries.
Cross-site scripting (XSS) happens when invalidated user input is sent into the response data of a client from a GraphQL server to steal personal information or carry out unauthorized operations on the client’s behalf.
An XSS attack can have several consequences, but the common ones are the transmission of sensitive data (cookies, session information, etc.) to the attacker or rerouting the victim to another website. Input validation and output encoding can help to reduce XSS attacks.
Poorly designed schemas may accidentally expose sensitive information to unauthorized users. Injection attacks can be caused by improper input validation. To spot and fix vulnerabilities in a schema and validation process, regular security assessments and tests must be carried out.
Furthermore, by utilizing the type system, servers and clients can easily notify developers once an invalid query is made, rather than depending on runtime inspections.
gRPC (Google Remote Procedure Calls)
tRPC (typed RPC)
OData (Open Data Protocol)
Transmitting sensitive information over insecure channels exposes it to possible tampering. Without proper encryption, such as the use of HTTPS, attackers can intercept and gain unauthorized access to sensitive data during transit. Poorly managed data transmission may cause data breaches, identity theft, or other malicious activities.
CORS is when a web application hosted on one domain attempts to make requests to an API hosted on another domain. By default, web browsers implement the same-origin policy to curb any potential security issues by preventing cross-origin requests.
With CORS, the server admin can specify which origin can access their resources. Any misconfiguration can cause unauthorized requests by attackers and exposure to private information.
Session management is the maintenance of stateful information about user interactions. Improper management of a user’s session can lead to vulnerabilities such as session hijacking. Issues in the generation, storage, or transmission of session tokens may disclose sensitive user data, threatening the integrity and confidentiality of user sessions.
Weak or poorly designed authentication and authorization systems can lead to unauthorized access, data breaches, and potential misuse of API functions.
In this guide, we covered some instances where GraphQL usage can result in performance challenges, schema complications, and intricate query issues. We’ve also provided guidelines to assist in deciding whether to implement GraphQL or REST architecture in your projects.
GraphQL is a powerful tool that offers several advantages over REST. However, if you prefer simplicity and faster performance, opting for REST architecture might be a better choice.
Keep in mind that the considerations outlined here may not be universally applicable, but it is worth considering them to determine their relevance to your specific situation.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on problematic GraphQL requests to quickly understand the root cause. In addition, you can track Apollo client state and inspect GraphQL queries' key-value pairs.
LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
55 Replies to "GraphQL vs. REST APIs: Why you shouldn’t use GraphQL"
I think all this article did was convince me that REST has hacks for things that GraphQL has natively. You argue, “There are many libraries by way of JSON API and JSON Schema” but when there is a library that solves a pain point for GraphQL your counter point is, “it means adding another dependency to manage your project”.
Your argument for performance and heavy queries is silly. If someone wants to do a heavy query, it’s more taxing on the server in the REST model because of the network overhead. Neither REST nor GraphQL are going to stop people from doing bad, bloated queries or sets of queries.
The whole idea is that REST constrains what you are allowed to query, whereas GraphQL is less constrained, with the potential for user provided queries which kill the back-end.
Fundamentally untrue. Can only be said by someone with a limited knowledge of graphql. Graphql is easier to strictly define than rest and constraints are easier to apply and uphold.
With OpenAPI and JSON Schema you can define HTTP APIs as strict as you like. The question is not about strictness of definitions, though. In HTTP APIs you expose resources and representations that solve clients’ needs, which you are sure will work correctly regardless of the load. GraphQL lacks any means to constrain the liberty of creating complex queries, apart from the manual implementation directly in the resolvers. I recently learned that even Facebook exposes only a predefined set of “allowed” queries, which means that if they, as the creators of this technology, can’t solve the problem, then you also won’t. This also means that this liberty of creating queries may be a small benefit in the beginning, but in the long run you will have more issues with constraining GraphQL to do ONLY what you wanted in the first place. HTTP APIs can do everything GraphQL does, but not the other way. You could even send GraphQL query as a per-resource GET media type and still have a HTTP API for everything else!
Github is imposing node count and rate limit restrictions for their GraphQL API. See https://docs.github.com/en/graphql/overview/resource-limitations.
Sure, they impose rate limits for their REST API too.
But considering that proxy/CDN per-URL caching works just fine for REST APIs and that GraphQL queries can produce much higher server load. consider such restrictions especially for you GraphQL APIs deployment.
I might consider using it after it’s mature enough like REST. Error handling only is not a small thing to me to mess with.
with GraphQL you can use persisted queries and receive them with GET. This way you can have them cached on CDN for each query+params combination.
This article made myself more convinced to use GraphQL, rather than re-inventing the wheel by implementing your own query language on top of a general REST interface.
GraphQL has potential but caches issues are a great problem
I don’t believe GraphQL has cache problems, it just depends on the architecture of your GraphQL application
Thank you for your perspective, maybe graphql is not yet the best tool in some occasions but it is possible that with the development of this query language in a near future graphql surpass rest, another perspective is given in this article that gives the opinion of using graphql or making co exist with rest https://www.imaginarycloud.com/blog/graphql-vs-rest/.
GraphQL is great etc but there will be certain use cases where REST may be more suitable.
In my case we have a Java backend ecommerce server that needs to Shopify API (they have REST and GraphQL APIs).
We GET all orders from a RESTorders endpoint and then UPDATE the status of the orders it’s processed. Same for the inventory REST endpoint.
For the most part those are the only endpoints our backend system needs to connect to, it can limit the fields it needs to request in the REST query and is unlikely to change the query and updates anytime soon.
If it used GraphQL it would need to install Ruby, migrate the build from ant to Gradle. So there will be a lot more complexities and additional dependancies to the runtime environment.
Also we only have dev team, small-ish project and we are consuming not building APIs so no need for the flexibility of GraphQL.
GraphQL and REST are ultimately tools and every tool has it’s use.
If I had the chance I would explain to every REST designer that this: “GET /books/1492030716?fields=title,pageCount” does NOT scale.
I’ve been working at a large payroll company where we have canonical representations of human resources which for example represent a ‘worker’. Those schemas are huge. Like 18.000 lines huge. You absolutely 100% don’t successfully whitelist those with a “fields” querysstring item. Nor do you successfully filter them with a $filter querystring item. It’s just too large.
Graphql is the way to go there.
how about sending a GET with something in the request body?
Using request body in a get request is bad practice
It depends on how many clients do you need to adapt. If you only have one client, let’s say a web page, which always displays 100 fields, then you don’t need to pass the fields to the API, just always return those 100 fields. If you have a lot clients to adapt, which will show different sets of fields, then it’s a different story. But even in multi-clients situation, you can still do the job using restful, design the url pattern like:
/worker/1/basic-info
/worker/1/family-info
“It may be done poorly” is not a compelling argument against any particular technology.
“It adds complexity” can be, but one assumes we are not talking trivial cases in arguments like this, so what’s really necessary is to show whether the complexity is significant on a serious project. GraphQL can drastically simplify the number and complexity of routes, e.g., versus a standard REST project.
Performance arguments can be as well, but again, you need an apples-to-apples comparison. A big part of the purpose of GraphQL is to eliminate the multiple round-trips. If that’s not a pain point for you, maybe it’s not necessary. But if it is, you’re going to end up building increasing numbers of REST calls to accommodate.
Possible, but not standard — https://stackoverflow.com/questions/978061/http-get-with-request-body
Agree but oData is worse than graphQL
Custom caching = more complexity. Just added a 3rd level of custom cache to our gql app.
“It may be done poorly” is not a compelling argument against any particular technology.
I think how frequently is a very important indication if not the most important against a tech stack, i looked at 3 graphQL implementations recently and they were all slow and terrible.
Something as simple as REST and its still done poorly in say half the cases for something as complex as GraphQL especially ins strongly typed languages id suggest the chance of a good outcome is very low and would certainly need management buy in to have a few goes at getting right.
They more I use graphql the less I like it. So far I couldn’t find anything that graphql does that REST wouldn’t do. Especially sucks java implementation of graphql: starting with outdated documentation and examples ending with their design choice of chain of builders of the builders of the builders… Nice try to generalize queries and put them under one umbrella, but it’s more pain than it’s worth.
If you want to query your API, why not SQL? See a POC at: https://github.com/zolyfarkas/jaxrs-spf4j-demo/wiki/AvroCalciteRest the advantage is that SQL is something everybody is already familiar with…
having used GraphQL, I see why a lot of new comers won’t bite this article, but in fact if you use it for a while, you’ll see why it can lead to some bloated APIs, moreover, I do think there are better alternatives, besides, think of who created it, Facebook, they created this piece of tech to suite their own needs, which I can argue is not what I would consider a general need, but rather driven by their business requirements. Things like using HTTP status codes, etc, these are important, and can in fact simplify clients significantly, but I guess for those who have not used it really, they won’t know these things, or yet they’ve got to stumble upon them.
Completely agree with Suhail Abood. GraphQL should not be seen as a general purpose REST replacement, which currently seems to be happening a lot. I am working on a new GraphQL API and it is already a big ugly mess with many issues that need to be resolved that would not have existed were it created in REST.
I think getting the full benefits from GraphQL requires a paradigm shift. GraphQL is inherently about type-driven design. It supports algebraic data types and this plays really nicely with functional programming languages that natively support AlgDTs. GraphQL also supports a Functional Domain Driven Design approach.
Also, if you use a GraphQL endpoint like Hasura, you can create end-to-end modelling of domain entities in your data. Dillon Kearns, a developer who uses Elm, discusses a “types without borders” benefit of GraphQL:
https://www.youtube.com/watch?v=memIRXFSNkU
When you take a deep type-driven design approach using AlgDTs as the basis for your data entities you get a whole host of benefits. This comment really says it all:
https://softwareengineering.stackexchange.com/questions/317587/is-it-still-valid-to-speak-about-anemic-model-in-the-context-of-functional-progr/317599#317599
Scott Wlashin doesn’t specifically mention GraphQL but everything in his talk is the background for thinking about GraphQL:
https://www.youtube.com/watch?v=1pSH8kElmM4
Scott also talks about creating APIs that give consumers feedback about what they can do, rather than just erroring what they can’t:
https://www.youtube.com/watch?v=fi1FsDW1QeY
Also, look at Richard Feldman’s talk “Making impossible states impossible”:
https://www.youtube.com/watch?v=IcgmSRJHu_8
I think that when you care deeply about type-driven design GraphQL makes a whole lot of sense. Especially if your language supports AlgDTs and type and function composition. As well as immutable data.
Also check this article out that links GraphQL with CQRS and Event Sourcing:
https://gist.github.com/OlegIlyenko/a5a9ab1b000ba0b5b1ad
There is also this awesome article that really helps to put CQRS and Event Sourcing into perspective:
https://gist.github.com/OlegIlyenko/a5a9ab1b000ba0b5b1ad
Check out Hasura GraphQL Endpoint:
https://blog.hasura.io/
I think GraphQL is just getting started.
“Performance issues with GraphQL queries”
This is exactly the reason why GraphQL is not bad, IT’S DANGEROUS.
GraphQL could work fine for small set of data. Some developers think that since they use the cloud then they don’t need a DBA so the end user could exploit the queries as they are pleased… Well, the cloud is metered (also it is not unlimited unless you want to pay really premium for that).
About DBA, even a server-less configuration needs a DBA (because AWS and Azure makes a poor DBA replacement). And if the project has a DBA, then he (or she) will say “nope!” to GraphQL.
In any case, it’s not rare to find rookies that does not even know about paging a query, so they load 1 million of rows to simply list 50 rows.
You are aware that you can have input parameter and valid them like how high a number can go, right?
There is no body in GET request according to the HTTP standard.
In what possible way is OData worse than GraphQL? It’s far more feature complete, makes all tasks simpler, handles errors beautifully, and handles update and deep inserts/updates seamlessly.
Graphl it is very bureaucratic and slows down development
Couldn’t you just use a separate endpoint for the requests that need specific return fields?
The request body in a GET request will most likely be ignored by the server.
https://stackoverflow.com/questions/978061/http-get-with-request-body
In rest you need to write your api, then write a swagger of the contract, then use a code generator for your client to finally have your api running between your server and client. There is several possible point of failure:
1. You can easily design your rest api the wrong way
2. You might be stuck in rest to find the right path url to link 2 or more concepts together
3. You might introduce mistakes writing the swagger and you need to document both the swagger and your code
4. Your client api generator might not generate exactly what is inside your swagger dropping some typings
5. The client generated might implicitly rely on way to post data which your server might not support (I had the problem with form and Autorest for instance)
With a GraphQL schema at least you do have a typed AND documented contract, thanks to the GraphQL standard your endpoint does not give you a lot for interpretation for your client.
@Aaron GET has no body!
Interesting, looks like we came full circle back to WCF+RIA Services that did SQL queries against WCF Rest services.
Not sure what you’re using, but in DotNet, you just build the service and the swagger is auto-generated. Nothing to keep in sync, no mistakes in swagger.
I feel hate to GraphQL and that someone hasn’t bothered to investigate properly
Agree with comments here – more reason to use it, than not
Just implement properly
Instead of only `fields`= why not:
`include`=
`exclude`=
Also 18k LINES in for a “worker” instance?!??! Really?
Your problem is modeling and design, at many levels, not technology.
Half of these complaints seem to be that GraphQL isn’t conducive to the kinds of bad habits that loose typing tends to bring.
Am I missing something?
I agree that GraphQL is not really the best solution in all cases. From what I’ve worked with, not even most cases. If you have to let the client limit fields you may have a use case for using this technology but, if not, the added complexity just adds headaches for the team. Not to mention teaching new team members how to use it and trying to explain to them that we can’t just rip it out. If you’re just doing a basic api for a web application rest is easier to work with. I can only say this against .net core. Maybe other technologies see graphql as a breath of fresh air but in .net core rest is really easy to implement.
The error part with graphql returning a 200 even when there are errors is a huge red flag for me. When I develop an api I want it to use those internet standards.
What are “internet standards” for error handling? In my opinion those differ per API. Sometimes I’ve seen RESTful APIs that always return 200s but in the event of an error the body of the response has the error information. I’ve seen that work well. Other APIs that are more “pure” use the HTTP response codes to codify errors. You still have a document how you’re using those and what they mean. GraphQL is no different. You get to choose the return payload and you can construct it in a way to communicate errors just fine, it’s just not with HTTP status codes because those don’t make as much sense with GraphQL since it is designed to be agnostic of the protocol over which it is communicated. Unlike rest, I think they have actually achieved something that can work outside of HTTP just fine. REST was supposed to be agnostic of the HTTP protocol in the original design, but it has become so tied to HTTP, I don’t know that it would work in any other system.
I’d say in the end, use the right tool for the right job. I think GraphQL solves a nice problem that is hard in REST to get consistently right. I don’t know that this article has really given GraphQL enough focus to see what it can really do. I personally have been involved in large RESTful API construction and it has worked fine, but as I’ve looked into GraphQL, there are lots of things native to it that we’ve had to spend a lot of time figuring out how to do correctly and maintainably in REST.
Look up RFC 7807 Problem API.
The title of this article is misleading and seems to contradict your conclusion.
Thanks for the tip — I can see how the conclusion was a bit confusing and seemed contradictory. It’s been reworded a bit to reflect the main focus of the article.
Exactly. It should have been “When to use GraphQL” but then no one would click it.
Hello, I came into a project using graphql and hasura. Front end developers wrote queries that kill the database. It is an incredible pain to debug as everything is 200, and then have to go look up the errors in Hasura UI (which is very buggy). Everything a post. Different schema results based on what the graphql query does. We are dropping GraphQL/hasura as a failed experiment. I gave it my best try, but GraphQL is a solution in search of a problem.
Sounds more like the problem is more that the backend team didn’t RTFM with GraphQL as opposed to GraphQL itself being the problem.
What you might want to do is use GraphQL schemas and design REST-like APIs and Endpoints.
Boom, all the performance benefits of using architectures exposed by REST to design efficient query patterns (using efficient indexes and joins on the database), with effectively free documentation to evolve your API.
No need to manually re-program yet another REST API and find manual / semi-automated ways to communicate changes if you can use GQL like REST. So much easier to deal with. One of the amazing features of GQL is the shared schema, and by god I’ll use it.
(yes I also have use and use GraphQL properly but it is often more expensive against databases and I wouldn’t use it for any high throughput solution)
Why is GraphQL Schema listed as a disadvantage? Schemas are a massive advantage of GraphQL: clearly define and validate requests, and build certainty into the response structure. Contract violations cannot occur in GraphQL; this is built into the framework. You also neglected to mention how GraphQL makes versioning much simpler.
Reading the performance issue part confuses me. At the end of the day, if the client needs that information, they’re going to get that information. So in REST they could equally just send a huge number of API requests trying to get all of the reviews for all books so they can filter by author.
I think you’re arguing that you could make a REST API specifically designed to grab this information they want, but you can equally do that in GraphQL. So say, as in your example, your goal is to get a list of users that have reviewed a given author. You could simply add a `reviewers` field onto the author object. `author.reviewers.name`. That’s now a “shortcut” to users who have reviewed that author.
That’s how GraphQL should be designed. It should be a densely weaved mesh of interconnectivity. Trying to stick to some “pure” resource based set of resolvers is going to be just as bad in GraphQL as it can be in “pure” REST APIs. If you need a connection to exist because a client needs it and you want it to be performant, THEN ADD IT! You would have to add that in REST, and you have to add it to GraphQL as well.
A huge part of GraphQL is shifting functionality complexity from the client to the server. You put more effort into the GraphQL design, and this allows your clients to be mindless by comparison.
RPC is what people want, REST is what they get. While it can do the job, REST is just a mistake in itself, there are so many possible points of frictions between creating a swagger (openAPI) properly, handling the errors, generating a compatible, typed client etc. that you better directly use an RPC protocol precisely made for this purpose. Unless you need high performances such as gRPC, GraphQL does this job as good as any RPC protocol (if not better)
I liked your point about the 200 ok results from GraphQL errors. Other articles I’ve read don’t mention this. One thing I would clarify is that sending multiple requests could be handled using REST but you would need to make those requests on the server and send them back in a single response to the client. The question would then become do I want to place the burden of handling these requests to multiple sources on the server or on the client?
A question I would like to ask you is, from the perspective of developing and maintaining your code, is it better to be consistent in your use of one approach or is it advisable to mix use of GraphQL and REST in your project? For example, some requests I make to my server only use the user’s email as an argument. This means I would need to write code for a schema, resolver, and a query when using GraphQL. It is it worth adding all this code to manage a simple request in order to maintain uniform use of GraphQL throughout my code? On the other hand if I use a mix of both approaches then my error handling will have to be different between GraphQL and REST calls. What do you advise?
You can have both worlds of REST and RPC in your GraphQL schema. It’s about finding the right balance for you team and finding a convention that sticks.
I put together some ideas, with examples, of using a REST base blueprint which I extend with RPC-inspired queries/mutations: https://medium.com/@olegkomarov_77860/how-to-tame-your-graphql-schema-f83d08de41ef
Thanks for replying and sending the article. I feel like if I’m always chasing the latest technology I’m learning something new but never really fully applying what I already know. Years ago I just got done learning REST. Then GraphQl came on the scene and I was banging my head against the wall because now I had to learn a new technology or be left behind in the dust. I really don’t know what RPC. But rather chasing an unfamiliar technology I’m just going to stick with what I know.