A question you should ask yourself at the start that I rarely here any discussion of: how much do you want to expose your backend data model to your front end(s)?
If your answer is "completely", which it sometimes is, then GraphQL might be a good option. It's only a question of implementation details.
If the answer is "not at all" then GraphQL is probably going to be a bad idea because that is the whole point of GraphQL.
The reason people don't realize this is because sadly most people's idea of a REST API is already just a plain 1-1 mapping from DB tables to JSON objects served over HTTP. If you're doing that, you're already coupling any front ends or other consumers to your data model, so what do you have to lose with GraphQL (other than the complexity of deploying it)?
When REST was coined the goal was to hide as much data model stuff as possible. This is really really important if your backend app needs a high degree of interoperability across organizational boundaries, because data migration is hard! But if your API is consumed only by a small number of components that your organization has total control over, you might not care that much.
Years ago I used to see people implementing crude remote procedure call patterns over HTTP because they thought that's what REST was, and had been told it was better because of reasons. But this wasn't a better way of doing remote procedure calls. It was a much worse way! Now I see people using frameworks that just expose all their DB models as HTTP endpoints because they think that's what REST is and have been told it's better. That isn't really what REST is, and GraphQL might be a better way of doing that if that's what you need.
REST is a bunch of constraints that make interoperability and scalability easy to achieve. Maybe you benefit from those constraints and maybe you don't. But that's what you need to think about before you think about GraphQL.
I've always found REST more logical. In a way, it's like the Unix philosophy...do one thing(at a time) and do it well. Implementing Graphql on the backend turns into a clusterf of spaghetti code real quick. And there are a lot of footguns.
I've noticed a lot of frontend folks especially like GraphQL, as they just want the data in as few calls as possible, which I can't fault them for.
I've read about an apollo bridge that basically does GQL over REST. I'm pretty curious how well that works, because it sounds like the best of both worlds. Clients who want GQL have it, clients that want REST have it, and backend logic itself is massively less complex.
Interestingly, the principle of single responsibility is specifically why I like GraphQL over REST. As your frontend complexity grows, your REST payloads tend to become carefully-balanced collections of complex shapes, and it becomes very difficult to maintain and refactor over time. In GQL, by comparison, each field or mutation has its own isolated implementation, authorization is handled at a granular level, and frontend queries can evolve as needed without imposing any significant need for changes on the backend.
REST is great for small, compact APIs which serve a couple of views, but as the product grows in scope and complexity, GraphQL ends up feeling significantly easier to keep straight.
The other thing is that it's very easy to build "complex" REST APIs on top of GraphQL - execute an internal query, reshape the result into a JSON payload to conform to the REST contract - but implementing GraphQL on top of a bunch of REST calls is a lot hairier. GraphQL feels more like a set of primitives, while REST is a coalesced interface.
They shouldn't be at odds with each other. GraphQL was explicitly designed to sit in front of your REST services - occupying the so-called backend for frontends (BFF) layer – allowing your service graph to be navigated by query in order to allow frontend folks to roll up all their calls in a single request to reduce the high round trip costs that can be found outside of the datacenter.
The Unix philosophy remains. You are still calling individual REST services, assuming you hold true to GraphQL's intent. The only difference is that the client is able to leverage GraphQL to push that work to inside of the datacenter, where latency is much more tolerable. If REST services are your individual Unix tools, the GraphQL resolver is the shell that ties them all together.
Granted, if your clients are known to be on solid connections you likely don't need to even bother with a BFF layer, but GraphQL comes from Facebook where a large segment of their users are on spotty mobile networks where round trip reduction is critical to providing a usable experience.
writing graphql resolvers by hand was what I did in ... 2017. I've been using postgraphile since and couldn't be happier. I don't think I've written a single line of Apollo in 5+ years.
And with postgraphile, and a remix/next BFF, you don't even need a backend!
I dont konw if this is a good practise. I start off initially with REST endpoints that expose (basic) data models - and then have the API the calls it needs. Over time there is a tendency to bloat your REST calls (a good sign is you need to combine two different models - joins). At this point what I have found useful is instead of putting a full blown layer graphql layer that does this scatter-gather for you - I add explicit "viewmodel" APIs. I am sure this was what graphql was for - but for some reason for me having explicit protos/rest specs to model your view models seems more incremental and less stressful. Or may be just old-school thinking?
How you model the data at rest does not need to match the GraphQL specification. The GraphQL specification should be similar to your REST entities but they have traversable edges to other entities.
This explanation is evident of a lack of understanding. I should know, because I felt exactly the way you do before I implemented a GraphQL server.
Unfortunately, I still don't know how to explain in words why your understanding is inaccurate, I only know how what it means in practice, by example. GraphQL is still elusive in that regard.
Happened to have worked with an API security product for a while that was sitting in front of a lot of large brands. One retailer that had APIs constantly under attack from bot and organized crime invested a lot of time and money into remapping their old rest API such that they could better protect the pieces of it in different ways.
Then, out of the blue, we learned they were moving everything to GraphQL because they had done cost analysis on how many fewer calls they'd need to make, creating efficiency gains of over 50% of all session transactions. What they failed to take into account was that all of the time and money invested in the prior methods to protect really relied on the structures of their REST schema. Now everything would need to build back up and many of the security introspection gates were within the chaining of the REST calls which could no longer happen.
It’s very much possible to keep your backend data model from leaking too much into your GraphQL schema, it’s just more work than for example using some kind of generator that creates a GraphQL schema from your database schema.
The harder thing in my experience is to make a GraphQL API that is performant across all edge cases and properly cost-limited. That takes an enormous amount of internal analytics infrastructure and work and is often not worth the effort.
And after all that effort, integrators don’t usually want to take the trouble to learn enough GraphQL to actually use the API.
I’ve come to the conclusion that GraphQL is a pretty good system for internal APIs for web and mobile, but a pretty poor one for public-facing APIs.
The issue I'm talking about is allowing clients to make arbitrary queries via GQL. Maybe I've misunderstood it, but that's how I've seen it used before. If clients can do that, then they need to know about the model. And if they can't then I'm not sure what GQL does that REST doesn't do.
My understanding is "arbitrary queries" <> "arbitrary _database_ queries". So you can have some abstract "graph" that can be queried, and separately implement "resolvers" (IIRC) that actually tie parts of the graph to actual queries. (So there is a layer of indirection.)
What you get is a way for clients to tell you precisely what fields it needs and a way for it to coalesce what would be multiple api calls in a REST world into a single request.
Thanks, that's a more nuanced understanding of it than I had. Still, when I try to think about keeping that model in sync with the real underlying model, it scares me.
It sounds to me like there is still bound to be some correlation between querying flexibility on the client side, and coupling between the client and server. But that is OK in many cases and in fact is how many REST apis are already being implemented.
GraphQL exposes your backend model the same way your json response to a REST api exposes the backend model - they dont. It's up to your REST api to assemble data from the database (or elsewhere) and return them in a structured format.
GraphQL resolvers do the same. You can hit another API, query a database, or return file data. It's up to you what you want each field to resolve to.
My conclusion is that there isn't much value in evaluating 1000s of perspectives, they're the same exact arguments you'd find in any blog or technical documentation comparing the two.
I actually found this very helpful. There’s so much cruft and bullshit and promotion among web frameworks and tech, it’s difficult to get a sense of what is the right decision if you’re new to web dev.
I’m surprised no one has mentioned the obvious interest of the author working for a company that provides REST tooling, reaching the conclusion that REST is a better option.
We use GraphQL internally but I admit I am currently more biased towards REST after battling with GraphQL, building a OpenAPI-based company, and playing with ergonomic REST-based frameworks like FastAPI. I still think the GraphQL DX is still miles ahead of OpenAPI and I really admire the best practices in GraphQL prescribed by Relay. But right now, REST is king for me.
Your observation is sort of the point of this article. Everyone has their opinion but nobody is de facto right.
You should have put a proper disclosure in the post to avoid speculation.
Also it seems off to do all this research, and then instead of summarizing it properly, throw evewrything away and finish it with your own sentiment.
I remeber there was a paper where the reserches asked students to implement the same API using either REST/HTTP, or GraphQL, and the conclusion were in favor of GraphQL.
I would've added reviews of the research papers on this subject, in addition to the social media posts. The former adding more rigor than the latter.
Fair points, I added a disclosure for clarity in future reference.
That being said, the Pro REST perspectives do scare me away from GraphQL in production. But seeing some posts about PostGraphile + Persisted Queries is interesting.
Also, research papers would have been nice to address but I am satisfied with the many hours this took to compile. A future follow-up may be necessary.
What noboody mentioned is that generic tools like AWS AppSync, PostGraphile, Hasura, etc. are actually anti-pattern for anything public facing, as they expose the data model and copy it as-is in GraphQL.
GraphQL server is a special case of the BFF pattern, and the whole purpose here is to decouple FE from the underlying data model on the BE, and let both to iterate faster without blocking each other.
Came across this blogpost that happens to describe where something like hasura sits and how it decouples product dev (app + bff) from data api (microservice + db) dev.
Think of Hasura as a GraphQL BFD (backend for data) instead of a GraphQL BFF.
> they expose the data model and copy it as-is in GraphQL.
> GraphQL server is a special case of the BFF pattern, and the whole purpose here is to decouple FE from the underlying data model on the BE, and let both to iterate faster without blocking each other.
> they expose the data model and copy it as-is in GraphQL.
This isn't inherently an anti-pattern.
> GraphQL server is a special case of the BFF pattern, and the whole purpose here is to decouple FE from the underlying data model on the BE, and let both to iterate faster without blocking each other.
A) Says who?
B) Why do we have to follow that specific dogma?
Who says that spaghetti code and Big Ball of Mud are anti-patterns? ;)
Why not to expose SQL interafce or DynamoDB API directly to the client? ;)
While tools like AWS AppSync, Hasura, & PostGraphile accelerate initial development, the bulk of SW Engineering costs are adding new features & providing ongoing support and maintenance.
I don't expose SQL to the client because my client apps don't have good SQL support, my database server doesn't scale connections well and it would take effort to properly lock down the SQL permissions.
That said, there are uses cases where this might be a good pattern - e.g. limited distribution internal tooling.
Direct access to SQL is a great example of something that is not an antipattern. It's just one approach of many, with strengths and weaknesses.
In my use-case adding new features and support is the majority of eng work. We find Hasura is valuable here in reducing the cost of doing so - especially compared to traditional REST implementations.
Personally I found GraphQL to be a God-sent for prototyping. Tools such as Hasura and postgraphile are just amazing to whip out fully-working backend very quickly. I do agree with some of the posts though about security being a bit of a hassle. It's not impossible to secure GraphQL endpoints (e.g. through row-level or column-level security for Postgres-based backend) but it's not as straight-forward as securing REST endpoint.
If you consume your own graphql endpoint you can add some layer of security by only allowing predefined queries and inspect the provided query variables. I use PostGraphile as an Express middleware and only allow whitelisted requests.
Regarding the “it’s not worth the extra complexity” argument, I think it depends on how you’re creating your GraphQL server. If you’re writing the server logic yourself, I think GraphQL is absolutely not worth the extra complexity. Making a REST server is way easier than making a GraphQL server.
But I think the balance can tip in favor of GraphQL if you’re using a managed GraphQL server like Hasura. I’m using Hasura for a solo project and I actually find it simpler than maintaining my own REST API code. All I need to do is specify my data model and never need to write any boiler plate for new endpoints. I know there are similar services for REST that can automate the boiler plate code away (like Supabase). But Hasura automates away the hard parts of GraphQL, and I prefer the experience as a client of GraphQL over REST. I like being able to specify exactly what data I want from the API and being able to get values for foreign tables in one query without needing to join the data client-side.
1. Apples vs Oranges: GraphQL is a protocol with an open spec, REST is an architectural style.
2. Nevermind how good or a bad GraphQL is, the de-facto standardization provides lots of benefits, in the same way as Docker did for containers.
3. GraphQL complexity is mostly an essential complexity in software engineering, with a bit of accidental complexity due to novelty and unaddressed problems/missing features.
4. GraphQL allows better modeling of the domain. It fits well to use with DDD/CQRS/ES/Sagas/Persistence Ignorance/TBUIs[1]. If all you need is a generic app managing a tabular collections of items, then you can use generic architectural styles like CRUD/REST/RDBMS/ACID transactions/ORM/generic Web Admin UIs, either coded manually, using AI copilots, nocode, or lowcode tools like Hasura or PostGraphile.
After 15 years of heavy restful API usage, building 10 restful API’s, using the GitHub and Shopify GraphQL API’s and providing our own GraphQL API in PHP, I think this article puts the nail on the head.
It is nice to only get the data you need as a client. The Graphiql explorer is very nice to try to get the right data. But that is mainly an advantage if the restful endpoints are badly designed. The Shopify API around inventory is very bad and became worse over time. You would need 15-20 rest requests or 1 complicated Graphql request to get the 3 fields you need together. But in most cases, even as a front end user, if the API is designed nicely it is not worth the complicated whole of the system of Graphql.
GitHub’s API works better as rest then as Graphql in my opinion. And the Stripe API is also very nice. I don’t need Graphql there as a user.
My main takeaway: GraphQL moderately improves developer enjoyment (DevEx) by majorly increasing the cost of making production ready APIs.
I've worked on bigger teams where the job was boring and there was plenty of spare capacity to improve DevEx. Spending a lot for a more enjoyable DevEx was worth it to retain good talent. They typically spent about 50% of their total capacity on DevEx and technical debt. Those teams would probably benefit a lot from GraphQL.
Other projects it's just me building an entire product with extremely tight timelines. Or it's a small team without a lot of spare capacity. I probably won't elect to use GraphQL in that situation.
It comes down to the right tool for the job. But the problem comes from scaling. I worked at a place that was using REST apis, but when they grew, they needed lots of bundling (or filtering down of excess data)d. Graphql gets bundling for almost free. While not unique, it also couples dataloaders, which essentially caches api calls on the request level.
Good ideas, but extra features require extra implementation.
One problem I’ve seen is graphql comes over for some high profile project needs. It feels elegant to get the fields you want in the way you want them.
The trouble comes when REST API parity is not maintained.
The dev experience then becomes an O(N) search through the autogenerated graphql docs to determine X is missing and the thing you are trying to do can’t be done elegantly.
We found that allowing the FE guys to iterate faster over relatively simple data models was worth the extra backend complexity. Additionally, every time a JSON deserialisation fails because someone typo'd a key an angel loses its wings, so that's nice to avoid.
GraphQL makes front end work easier because FE folks can't seem to handle the complexity involved in making multiple calls to a backend. GraphQL moves that complexity somewhere else (ie: the backend).
From a BE POV GraphQL makes things more difficult because the failure behavior is more complicated. If a failure occurred in the FE then the FE presumably knows what to do. If a failure occurs in a graphql call chain it's unclear what the FE would like to happen, and the FE developer is probably clueless as to what they want, since the structure has been abstracted away.
Btw. If you're building a GraphQL API using TypeScript, you should take a look at garph (https://garph.dev) which helps you to create type-safe GraphQL APIs without code-gen
If your answer is "completely", which it sometimes is, then GraphQL might be a good option. It's only a question of implementation details.
If the answer is "not at all" then GraphQL is probably going to be a bad idea because that is the whole point of GraphQL.
The reason people don't realize this is because sadly most people's idea of a REST API is already just a plain 1-1 mapping from DB tables to JSON objects served over HTTP. If you're doing that, you're already coupling any front ends or other consumers to your data model, so what do you have to lose with GraphQL (other than the complexity of deploying it)?
When REST was coined the goal was to hide as much data model stuff as possible. This is really really important if your backend app needs a high degree of interoperability across organizational boundaries, because data migration is hard! But if your API is consumed only by a small number of components that your organization has total control over, you might not care that much.
Years ago I used to see people implementing crude remote procedure call patterns over HTTP because they thought that's what REST was, and had been told it was better because of reasons. But this wasn't a better way of doing remote procedure calls. It was a much worse way! Now I see people using frameworks that just expose all their DB models as HTTP endpoints because they think that's what REST is and have been told it's better. That isn't really what REST is, and GraphQL might be a better way of doing that if that's what you need.
REST is a bunch of constraints that make interoperability and scalability easy to achieve. Maybe you benefit from those constraints and maybe you don't. But that's what you need to think about before you think about GraphQL.