Esteban Herrera Family man. Java and JavaScript developer. Swift and VR/AR hobbyist. Like books, movies, and still trying many things. Find me at eherrera.net

GraphQL vs. REST APIs: Why you shouldn’t use GraphQL

6 min read 1873

Graphql VS Rest API

Editor’s note: This post was last updated on 24 August 2022 to verify code accuracy. 

GraphQL is great if you want to work in a declarative style, enabling you to select only the information or operations you need. However, depending on your use case, performance requirements, and tolerance for unnecessary complexity, GraphQL might not be the right fit for your project.

In this article, we’ll review some reasons why you should consider using a REST architecture instead of GraphQL. We’ll discuss the drawbacks of using GraphQL, including performance issues, problems with GraphQL schemas, and complex queries. We’ll also outline some common use cases for GraphQL and provide some tips to help you determine when to use GraphQL vs. REST. Let’s get started!

GraphQL vs. REST: Differences

The biggest difference between GraphQL and REST is the manner in which data is sent to the client. In a REST architecture, the client makes an HTTP request and data is sent as an HTTP response, while in GraphQL, the client requests data with queries.

It’s also worth noting that in REST, the structure of the request object is defined on the server. In GraphL, you define the object on the client.

When should you use GraphQL?

GraphQL is an excellent solution to a unique problem around building and consuming APIs. When used as designed, it can be an ideal tool for the use cases described below.

Data fetching control

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 requested by the client. If you want the client to control the type and amount of data it needs, GraphQL would be ideal for your project.

Using multiple data sources

GraphQL simplifies the task of 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.

Alleviating bandwidth concerns

Bandwidth is a problem for small devices like mobile phones, smartwatches, and IoT devices that are not able to 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 could reduce the app’s performance when bandwidth is limited.

Rapid prototyping

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. So, if your UI changes, for example, requiring either more or less data, it doesn’t have an impact or require changes on the server.

When should you use a REST API?

Now that we’ve outlined some use cases that call for using GraphQL, let’s discuss some reasons why you might want to consider using REST instead, reviewing some tips to help you determine when to use each.

GraphQL performance issues

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, for example, 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 retrieve the data in an efficient way.



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. Any of these solutions will depend on the library you’re using.

REST can do much of what GraphQL does

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 receiving 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, then implementing the parsing and returning logic yourself:

GET /books/1492030716?fields=title,pageCount

Thankfully, this is easy to implement, thanks to the many JSON API libraries that are available in many languages. If you want the benefit of using a schema and strong types in REST, you can use JSON schemas; there are many libraries that implement and support JSON schemas.

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. OData 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 exceptional 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 make things more complicated in its own way, which we’ll discuss next.

GraphQL makes some tasks more complex

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 types, queries, mutators, resolvers, and higher-order components,

From a maintenance perspective, this is especially detrimental. 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 executed successfully, 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.


More great articles from LogRocket:


GraphQL vs. REST: Web cache

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.

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.

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, usually an HTTP POST endpoint, where all the queries are sent. Since each query can be different, it’s harder to use this type of caching. 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, however, it is still widely used and will work for the purposes of this tutorial.

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 schemas

By allowing you to define a schema, GraphQL gives you a lot of benefits like automatic validation and introspection. Depending on how you choose to 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.

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. 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.

Error handling and tooling

Error handling in REST is easier when compared to GraphQL. RESTful APIs follow the HTTP spec with regards to resources and returns various HTTP statues for various API request states. GraphQL, on the other hand, 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.

Conclusion

GraphQL is a powerful tool, and there are many reasons you might choose GraphQL over REST. But, if your tolerance for slow performance and complexity are low, you might want to steer clear and consider using a REST architecture instead.

In this guide, we covered some scenarios in which using GraphQL could lead to performance issues and problems related to schemas and complex queries. We also offered some tips to help you determine when to use GraphQL and when to use a REST architecture.

The points I’ve presented here may not always apply, but it is worth taking them into account to see if they can be addressed.

Monitor failed and slow GraphQL requests in production

While GraphQL has some features for debugging requests and responses, making sure GraphQL reliably serves resources to your production app is where things get tougher. If you’re interested in ensuring network requests to the backend or third party services are successful, try LogRocket.https://logrocket.com/signup/

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. .
Esteban Herrera Family man. Java and JavaScript developer. Swift and VR/AR hobbyist. Like books, movies, and still trying many things. Find me at eherrera.net

46 Replies to “GraphQL vs. REST APIs: Why you shouldn’t use GraphQL”

  1. 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.

    1. 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.

      1. 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.

        1. 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!

        2. 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.

  2. 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.

  3. 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/.

  4. 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.

  5. 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.

    1. 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

  6. “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.

  7. “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.

  8. 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.

  9. 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.

  10. 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.

  11. 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.

  12. “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.

  13. 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.

  14. 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.

  15. Interesting, looks like we came full circle back to WCF+RIA Services that did SQL queries against WCF Rest services.

  16. 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.

  17. 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

  18. 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.

  19. 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?

  20. 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.

    1. 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.

    1. 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.

  21. 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.

  22. 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)

Leave a Reply