Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
GraphQL vs. REST APIs: a complete guide (airplane.dev)
106 points by makaimc on March 3, 2023 | hide | past | favorite | 96 comments


Here's how you do it:

- REST/Hypermedia when you're actually building a website (not app) and your "site" is a state machine

- OpenAPI when you expose and API to 3rd parties

- Isomorphic TypeScript APIs when you're using TS on both backend and frontend [0]

- GraphQL when the frontend needs to talk to an API layer provided by different teams

- OpenAPI when one backend talks to another backend

- gRPC might be an option, but most teams don't need it

[0]: https://wundergraph.com/blog/isomorphic_typescript_apis_end_...


Simplify that to:

- REST by default

- everything else might be an option, but you need to justify it with specific reasons.

Also, having a JS-driven front end or multiple teams is not an automatic justification for the complexity of GraphQL.

GraphQL is a huge burden, for very little practical gain. Most companies have very small number of examples of conflict areas where queries need to be optimized, and for the most part, these can be resolved through smarter front-end engineering (like not throwing React at CRUD websites).

It's amazing how we managed to build large-scale websites with essentially all modern functionality without all of this stuff for years and years, and only since 2012 or so have these tools become "necessary" (and I'm being generous with 2012...it's more recent than that).


> GraphQL is a huge burden

I’ve recently been bolting graphql support onto a midsize legacy webapp with the goal of making native mobile apps easier, and so far I’ve been finding it remarkably simple and delightful — In fact implementing a graphql API so that the clients can specify which data they want for themselves has taken less time than all the design dicsussions about what a REST API could potentially look like…

(edit: originally I asked how it was a burden, but after refreshing the page I see this was already discussed in another subthread, so I’ll just throw in my anecdote without asking any question :) )


It's one those "the first taste is free" kind of things. If you're just doing the transition now, you'll have to take my word that there's more pain coming. It also matters a lot what you mean by "bolting on"...is anyone on the team actually using it?

I will freely admit that, depending on the size of the team and the scale of the app, YMMV. For example, if you're the only person working on a legacy app that isn't under high load or lots of regular change, it probably doesn't matter what technology you use. At the extreme other end, the best tech in the world can be an impossible lift for a high-load service with a huge team supporting it.

Most of the parasitic complexity, in my experience, comes not from GQL itself, so much as the downstream burdens that come with maintaining the infrastructure needed to service the GQL. Everything being a POST, for example -- hope you don't like cacheing!


Also it matters, what kind of security requirements there are. Is it an API, that everyone can query to their heart's content? Or is there stuff some people may access and others are not allowed to see? Then suddenly there is a whole security layer in the game, that needs to be carefully implemented and tested. Did the thing I implement really protect the data of the API from all possible accesses by unauthorized people?


> GraphQL is a huge burden, for very little practical gain. Most companies have very small number of examples of conflict areas where queries need to be optimized, and for the most part, these can be resolved through smarter front-end engineering (like not throwing React at CRUD websites).

We use Hasura to provide GraphQL and find the exact opposite.

* Need to filter by X? Already done.

* Want to join two different entities? Done.

* Pagination? Done.

* Aggregation? Done.

* Security? Done, just set it.

* Streaming data? Done.

We don't have traditional API code, and yet have an API is more sophisticated and powerful than any API I've built professionally.


Caching as an option is also good.


I more or less agree, but recent advances in tooling has changed this. E.g we've built a GraphQL to JSON RPC compiler [0], so we're hiding GraphQL behind a JSON RPC wall which also enables powerful code generation. We're using this successfully to build our own cloud [1] using our own tooling and I quite like it.

Shameless plug, I'd love to get feedback if you have the time to try it out.

[0]: https://docs.wundergraph.com/docs/features/graphql-to-json-r...

[1]: https://cloud.wundergraph.com


I mean...ok, but...wow. You built a compiler?? For writing a web app? And you're not Facebook?

Look, maybe this is totally appropriate for your application domain. I don't know. But this kind of "power" is immensely complex. We have to be honest about the costs.

I have to keep reminding people that essentially all functionality of the modern web existed prior to 2012.


Their entire company is developer tooling with GraphQL, so it's not like they made a compiler for their own specific web app; they're selling their service. I agree if you're just making a run of the mill web app that it's crazy but they're an infrastructure company, not a web app company.


Maybe I'm just not understanding the use case here but your using graphql with a compiler to produce rest (JSON RPC) endpoints? Why not just write rest endpoints? I can see how it might be easy for simple endpoints but as soon as you have to optimize anything you'll need to add features to your compiler.


Sometimes we just need to create another immensly complex layer on top of something, because the 10-year-old boring technology that already works is lame.


I haven't used it a lot but one of the benefits of GraphQL that caught my eye is you get to specify what you want returned. So, for example, instead of 20 product objects (all available properties) you can get 20 products with name and price.

Also, as I understand it, when implemented properly, you can get more complex (?) data back. For example, instead of getting 10 orders, and then 10 more requests for the items for each order, you can make a single request and get both in a single response.

I believe both concepts apply to creates / updates as well.


> but one of the benefits of GraphQL that caught my eye is you get to specify what you want returned. So, for example, instead of 20 product objects (all available properties) you can get 20 products with name and price.

Sort of (the sibling comment explains well why this example is an illusion). But even if this were an advantage, you have to implement the logic (simple in this case, but not so simple once people go hog-wild with the GQL). Also, I don't think I've ever had a situation in my career where loading name and price is a significant burden over either field individually. On the other hand, it's a huge burden to have to implement the back-end system that supports a fully orthogonal, structured query language for the UI.

To be fully charitable to the argument you're making, probably the real reason people do this is because they want to decouple development between Team UI and Team Product and Team Pricing, and it's just "easier" to expose "web SQL" to Team UI and let them go nuts, rather than sitting down with them an exposing targeted endpoints that give them exactly what they need.

...but now you have N problems. Your web app has become an ad-hoc distributed query language executor, and you have to think about the semantics and load implications of all of that.


> probably the real reason people do this is because they want to decouple development between Team UI and Team Product and Team Pricing, and it's just "easier" to expose "web SQL" to Team UI and let them go nuts, rather than sitting down with them an exposing targeted endpoints that give them exactly what they need.

That's the only reason why teams use GraphQL. Decoupling taken to the extreme.


That's not an advantage, from the DB side the two queries are indistinguishable because they use the same indexes. They will take virtually the same CPU to complete.

If your user has authorization to access this extra data, the actual cost of sending those extra fields properties over the wire is ridiculously trivial.

Think a kilobyte or two, if not a few bytes.

Any justification you think you have for just sending the name + price is utter bullshit. You would save vastly more in bandwidth by not sending whatever dumb graphql code you wrote as part of your front-end build.

That is, unless you are Facebook or Google and have already optimized the hell out of your front-end libraries.

Which I guarantee you aren't and haven't done.


I'm not worried about the DB. Less down the pipe to the browser or app means the user can get to see something sooner. It also mean less for the hardware / browser + JS to swallow.

Minor? Maybe.

Until you have users with less powerful mobile devices using less than ideal wifi / internet connections.

If work provides you with a new device (either as a company perk or because you're well paid) and you live in a major city where mobile data speeds are great these things don't matter. For most everyone else they do.

I suppose this explains why so many mobile experiences are so bad? People like you feel the user experience is "utter bullshit". Shame on you.


Not at all - removing select “*” from queries is perhaps the lowest hanging fruit for optimizing queries.

https://stackoverflow.com/a/25093454

I agree that GraphQL is often overkill but specifying fields is powerful and sometimes a big boon.


That's not true unfortunately.

Posting a SO Question that's been upvoted by 24 people in a decade is not evidence.

Think about this a bit more, those are LOCAL network calls you're talking about. Not calls over the internet.

It doesn't matter.

Obviously if there's a massive blob in your DB table you're not going to be sending it up regardless if you are using graphQL or not.


How is GQL a "huge burden"? Would you care to elaborate?


I could write a book on this, but just a few:

* your teams will now spend a big portion of their time thinking about GQL primitives and mapping and syntax (oh my) and otherwise caring for and feeding this beast.

* you still haven't solved the underlying problem -- you still have to figure out why your GQL requests are hammering the back-end(s...let's not forget that a lot of this stuff came from poor decision-making re: microservices!), only now it's indirected and harder to optimize.

* ...oops, you forgot to implement all the corner cases of your GQL schema! Go back to 1 and start over.

Say what you will about REST, but the syntax is dead simple, it takes about 15 minutes to learn, and the semantics are crystal clear. Whatever complexity remains is actual complexity in your problem or org structure, and you should probably just fix that instead of trying to find magical tech beans to abstract the problem away.


> * your teams will now spend a big portion of their time thinking about GQL primitives and mapping and syntax (oh my) and otherwise caring for and feeding this beast.

What exactly do you mean by this? My team spends exactly zero time "thinking about GQL primitives and mapping and syntax"? What programmers have a problem understanding GQL syntax? I have explained GQL and set people to work in a 30 minute session. I've even had non-technical people write automated tests for APIs. If they can't write the queries themselves, they can simply use any of the great query builders(like apollo studio or what have you), where they can quite literally explore the entire schema, with documentation, and point-and-click their way through building any query.

> * you still haven't solved the underlying problem -- you still have to figure out why your GQL requests are hammering the back-end(s...let's not forget that a lot of this stuff came from poor decision-making re: microservices!), only now it's indirected and harder to optimize.

How is this really any easier with RESTish APIs? In the end, this boils down to how you are doing observability. If you don't do any observability, you are shit out of luck whether you use GQL or REST. With GQL, you can quite literally automatically instrument your entire schema and get detailed tracing information for your entire graph. I have sentry set up to trace all our requests from our frontend, to our GQL gateway, to the subgraphs, to other services they call out to and even time taken doing database queries. It was a few lines of code.

> * ...oops, you forgot to implement all the corner cases of your GQL schema! Go back to 1 and start over.

Corner cases? If you have some underlying data you need to expose, the difficulty of exposing this data in the most appropriate manner comes down to the complexity of your data, and whether you use GQL or REST to expose it doesn't really change it. With GQL, types and relations are at least "native" - they are the source of truth. With REST and something like OpenAPI, you'll constantly be fighting limitations and have to trawl through hundreds of endpoints, some of which might be doing extra stuff for the sake of ease of consumers, etc. Feel free to elaborate on what sort of corner cases you have in mind. This sort of vague hand-waving isn't really useful.


I don't want to get into a debate about this. I've told you what I believe and why I believe it.

I will add this: if you are truly at a company that has adopted GQL and you are not spending significant eng time on it, you're either not measuring it (ding ding ding!), or you're in the vast minority. Or maybe you're just too early, I suppose. Perhaps relevant to that point: the complexity of explaining GQL to an unfamiliar developer is not what I'm talking about. Most people can learn enough GQL to make really awesome footguns in a single 30 minute session!

REST is easier because, instead of having to do all of that instrumentation you're talking about across an entire query graph (you've described quite a lot of infrastructure there, btw...), you have endpoints, which correspond to specific needs, which you can then optimize appropriately on a case-by-case basis.

When all you expose is a structured query language that anyone can use, you have made things (perhaps) easier on a single dimension (consistent interface), but you have abstracted all of the other problems and made them harder. And you have all of this other infrastructure to look after now, too.


> I don't want to get into a debate about this. I've told you what I believe and why I believe it.

You've told me what you believe, but not why. You just made vague, handwavy assertions about things that you clearly understand rather poorly. Obviously you don't want to debate this, since your arguments are those of a flat-earther trying to explain their views.

> I will add this: if you are truly at a company that has adopted GQL and you are not spending significant eng time on it, you're either not measuring it (ding ding ding!),

This is just silly. You're just making assumptions about things you know nothing about. GQL lets us be a lot more efficient. The libraries for building GQL resolvers make it easy for full-stack devs to build new endpoints, and since modern tooling can integrate tightly with the underlying database technologies, no one is building footguns; all queries that are generated are optimized automatically and there are no N+1 issues. Any frontend dev just writes a GQL query, types are generated automatically and the results of querying the API are fully typed. Every modification to the API can be checked and diffed and we can be warned about recent clients that might be broken by the change. It's not only a breeze; it's brilliant and a joy to work with.

> Perhaps relevant to that point: the complexity of explaining GQL to an unfamiliar developer is not what I'm talking about. Most people can learn enough GQL to make really awesome footguns in a single 30 minute session!

This is even more silly. It's not possible to build GQL query footguns. Whether a query is a footgun is entirely dependent on the underlying resolver. If you build poor resolvers, then someone can build footguns just fine, but as I just explained, this doesn't have to be a problem. You know what is also a footgun? Frontend developers making N+1 requests from the frontend, hammering your API unnecessarily and possibly getting inconsistent data because the multiple different requests aren't necessarily looking at the same data.

> REST is easier because, instead of having to do all of that instrumentation you're talking about across an entire query graph, [..] you have endpoints, which correspond to specific needs, which you can then optimize appropriately on a case-by-case basis.

Yes, and what sort of endpoints do people end up writing? Either they 1) add a bespoke query language via query parameters or some such to conditionally expand nested relations, which I've already explained elsewhere is not-very-standardized, poorly supported by tooling like OpenAPI and in the end just GQL done poorly, 2) they add bespoke endpoints with nested relationships already expanded resulting in an incredibly poor API that takes a dump on REST principles or 3) they just make a bunch of requests from the frontend, which I've already explained is also bad.

What I am describing in terms of instrumentation is no different from what something like sentry can do with any normal REST API(it can hook into and, say, instrument all your express.js calls), except that a GQL schema is an introspectable, "executable" data-structure which automatically contains all the type information you need to make instrumentation great. I can tell you the number of milliseconds it takes to query for every single field in my entire graph. And all this is literally a couple of lines of code,

> (you've described quite a lot of infrastructure there, btw...),

I'm not describing infrastructure for observability. I'm describing the system I'm working on. If you think you can make judgments about our system architecture based on a single line description, I think that speaks volumes on its own. You can do better than this.

> When all you expose is a structured query language that anyone can use, you have made things (perhaps) easier on a single dimension (consistent interface), but you have abstracted all of the other problems and made them harder. And you have all of this other infrastructure to look after now, too.

Now you're just latching on to our infrastructure again, probably because you understand GQL so poorly that you think that using GQL automatically comes with the infrastructure I described. It does not. A simple GQL API is at least as simple as a simple REST API, at least when viewed from the lens that it automatically comes with documentation for your API and a rich ecosystem to communicate with it in well-typed manner. Contrast that with a simple REST endpoint which just returns unstructured data without any type information attached.

I think it's me who has lost interest now, because from my perspective, it is abundantly clear that you've never actually really worked with GQL, and you're just arguing from a place of uncertainty because you're scared of looking into new technologies -- after all, why would we ever change something that works? It's just all hot garbage, right? Or possibly you're just parroting someone else's equally poorly informed arguments that you've read somewhere.

I will extend this little olive branch, however: It's entirely possible to build poor GQL APIs, where some of your arguments would have some merit(if interpreted very charitably), but the reason it's even barely worth mentioning is that this literally applies to everything, and REST APIs are part of that set.


> It's not possible to build GQL query footguns.

GQL literally allows unbounded queries.

All the "tooling" around like "field complexity", "data loaders" and other hacks are literally that: hacks and workarounds, and they are not even consistently, evenly or even efficiently implemented among the various GQL libraries and frameworks.

> it automatically comes with documentation for your API

Unless it's specified in code, and to create actual documentation you have to run a server, connect to it with a tool, and dump it (can't remember which lib did that, was it in Java or in Go).

> you think that using GQL automatically comes with the infrastructure I described.

This: GQL doesn't come with infra. And for every thing that REST aready has and for every issue that GQL has, and REST doesn't, you need to add more and more infrastructure and "rich ecosystem":

- Caching is literally built-in in HTTP. GraphQL's default method is POST, so to "solve" caching frameworks like Apollo have to act as middlemen unpacking every incoming request and every outgoing response looking for certain fields to figure out what to cache. Of course, this isn't available in other libs and framewroks

- Unbounded queries are literally not an issue in REST (unless you build something weird). In GraphQL you need to "specify field complexity" if you framework allows that

- Your REST endpoints know what exactly is requested, and can have specific hyperoptimised queries for that specific thing. GraphQL is ad-hoc by nature, any query is potentially n+1, so you have the workarounds with dataloaders which by definition cannot be optimised unless your specific framewrok gives additional insights into what's being requested.

Literally everything around GraphQL is "nothing works well, and if you're lucky, a particular graphql implementation for your programming language will have some solutions for some of the problems".

How do I know?

I built a service prototype for an internal tool in 5 different languages with 6 different libs:

- Typescript, Apollo

- Java, graphql-java

- C#, graphql-dotnet

- go, glgen and graphql-gp

- Elixir, absinthe

GraphQL sucks ass for everyting and everybody except client developers who couldn't care less how it looks on the backend


1) If you're building an internal tool... why do you care about 'hyperoptimised queries'?

2) Try Hasura (or similar).

Sure, if your goal is 'I want to hand write hyper-optimized queries for every imaginable use-case' then graphql sucks. That's not what it's designed to do.

If your goal is to fast front-end development, reasonable efficient network usage, and combining different services together it's great. Tools like Hasura go an extra mile and offload a lot of work from the BE team.


The problem is:

REST = http

GraphQL = http + GQL + resolvers

Sure, one more layer of abstraction here and there may be justified. In the case of GraphQL, it's not.


GQL, in no particular order:

- GQL allows unbounded arbitrary queries. The awkward workarounds turn it into REST with none of REST semantics

- default query method (POST) cannot be cached by literally anything in the infrastructure because POST is not cacheable by definition. The awkward workarounds require you to parse and look up fields in both request and response. Both of them arbitrarily large.

- instead of delegating requests to optimized queries (db or services) you now collect all that data manually, in-memory, on the server with little to no insight into what the data is, and how to optimize its retrieval

- default types doesn't provide useful primitives like dates

- you now have to keep up with evolution of every single microservices you depend on

There's more that I've forgotten.

It's really good for building internal tools that usually have different requirements than what existing APIs provide you


> - GQL allows unbounded arbitrary queries. The awkward workarounds turn it into REST with none of REST semantics

This is essentially a solved problem. You simply give all your fields a complexity value and then you limit the allowed complexity.

> - instead of delegating requests to optimized queries (db or services) you now collect all that data manually, in-memory, on the server with little to no insight into what the data is, and how to optimize its retrieval

Or you simply integrate tightly with an ORM or something and generate optimized queries from your GQL queries.

> - default types doesn't provide useful primitives like dates

Just not really an issue in practice, and really comes down to the underlying transport medium. JSON is limited. If you send a date over the string, it's either going to be a timestamp or a string. Your consumer will still need to know it's actually a date that needs to be deserialized. At least in GQL this is easy to do.

> - you now have to keep up with evolution of every single microservices you depend on

How is this a problem with GQL? Do you think that API versioning is in any way easier to when you have REST APIs? It's actually the opposite, because OpenAPI schemas suck and there is no great tooling that helps you stay on top of the changes. In contrast, there is excellent tooling for GQL that literally diff your new schema vs the old and tell you if any recent clients would be affected. You can do all this as part of your workflow(in CI etc) and act accordingly.


> This is essentially a solved problem. You simply

> you simply integrate

> or something

"simply", "essentially", "something". An equivalent of "just".

In reality: none of this is solved, non of this is "simply" etc. because every single lib and framework (often multiple for a language) will have their own awkward workarounds for these "solved" problems.

> Just not really an issue in practice, and really comes down to the underlying transport medium. JSON is limited

It is an issue in practice because every single framework does implement a date/time/datetime extension to built-in types. And this has nothing to do with JSON. Every single modern protocl for some reason forgets that dates, times and timestamps are sued everywhere and by everyone. See protobuf for example. Encodes to binary, has no dat representation.

> How is this a problem with GQL? Do you think that API versioning is in any way easier to when you have REST APIs?

Yes. API versioning is easy with REST API. You can even evolve schema versions for the same resource without ever changing the endpoint by looking at "Accepts" headers. When you have ad-hoc clients doing ad-hoc queries with GQL you can't even be sure which particular subset of data is requested by whom, and can you remove or deprecate or change it.

Yeah, yeah, here the "solution" is to use a hack called "persisted queries" which is literally REST but with all the good parts removed, and a lot of unnecessary steps added.


Do teams tend to use GraphQL Schema to synchronize syntactic expectations between FE and BE?

My experience in doing so is limited, but I do know that this synchronization tends to be difficult and really like the idea of an explicit contract-based synchronization strategy.

It seems like a very big potential benefit but again, I don’t have enough direct experience doing too so be willing to put much stake in defending it.


There is a fair amount of practical gain in terms of specifying fields. Can go a long way in terms of making flexible endpoints that don’t pass around extra data. This often isn’t necessary. But when it is you would cry at the thought of using REST instead.


I can think of painful examples in REST in my life where I had an endpoint that was being used for something new, and now I had to join with some new data model to solve the new problem which made the old use sub-optimal (or vice-versa).

But when that happened, what it really told me was that it was time to introduce a new endpoint and refactor the code to adapt to the change in use case. Painful? Sure. But so are the downstream consequences of converting everything in your system to an arbitrary query executor.


Right. In GraphQL you wouldn’t need to make a new endpoint for the same resource just because you’re calling it for a different purpose. It separates the API from how it’s used.

If you’re querying different fields on the same resource 50 different times it’s rather absurd to keep making new endpoints.


> GraphQL you wouldn’t need to make a new endpoint for the same resource just because you’re calling it for a different purpose.

Yes, but I'm saying that's a feature, not a bug.

It's not absurd to make new endpoints. Each endpoint is a different need. You can optimize them independently...or not.

> If you’re querying different fields on the same resource 50 different times it’s rather absurd to keep making new endpoints.

In my career, I can count the number of times that a field has mattered in a response on one hand. Usually the problem is the joins, or the total number of queries. Point being: you don't generally write new endpoints just because the number of fields in a response is slightly different.


Or you can use GraphQL and get all of that functionality for free.


Where "free" means "lots of developer burden", sure.

Let's kill this fly with a chainsaw. It's free!


I've never experienced the problems you say you have with GraphQL, to be honest, and I've been using it for quite a while.


You can modify REST endpoints to support selects and filters.


One thing Id suggest - "gRPC might be an option but most teams dont need it" - needs a revisit. As a backend-dev (who does front end when needed - and that too by slapping NextJS on an API) I have found starting from a grpc set of services and generating http/openapi specs from it to be much for maintainable and understandable than starting with the OpenAPI spec and working "inwards". Apart from a (mostly) single source of truth for my interface intent - I also get a system that is amenable to scalability concerns than most of the time when I started working inwards. I might be in the minority as most folks who build services come from a product background?


If we compare gRPC to OpenAPI, we get the following. gRPC will be faster at the tradeoff of complexity. You need more tooling, you cannot easily inspect binary traffic, you cannot simply call gRPC from the web, you need a grpc web proxy, proxies and API gateways are more complex for gRPC than for an OpenAPI/REST-ish API, and the list goes on. I can put my protobuf in a registry, but the same applies to OpenAPI. So what really is the difference? And do we really need the gRPC level of performance with this hefty price of complexity? I doubt it. Most of the time, your database will be much slower than what gRPC might give you in performance compared to OpenAPI.

Sorry if I'm pushing back on this. It's not against you. I've just seen way too many devs and teams who created gRPC "micro" services and all they needed was one boring well designed OpenAPI monolith with good architecture.

gRPC is great if you really really have the problems it tries to solve. I believe most companies have a much bigger problem than performance, the inability to design APIs. You cannot solve bad API design by using a faster tool. Fix your API design, OpenAPI is great.


Here's a bunch of random points (this deserves a full blog post)

- it's not about performance

- OpenAPI needs and has tooling (it just doesn't work) - think about documentation, client/server code and evolution support for forward/backward compatibility, type safety, etc.

- you can build monoliths and microservices with both

- gRPC / protobuf gives you a pragmatic separation of concerns (and typing among other things)

- gRPC allows exposing REST/OpenAPI with defualt tooling and it works

- there's an extensive set of best practices that combine the best of both worlds - just read https://google.aip.dev/

- if the workd prefers GraphQL, you're out of luck

- gRPC / protobuf help you focus on the actual contract and make everything else (that's 90% of time) a non-problem.

---

Disclaimer: I'm in the grpc (and protobuf) camp and have built APIs with REST, Thrift and gRPC/Protobuf for more than 15 years (gRPC mostly last 5 years) As an infrastructure startup we have to both expose and consume both REST and gRPC.

If you build APIs and decide to handle the above manually - you must feel productive doing work that compilers and code automation tools have been invented for. However tooling should automate it for you.


Pushback is always good. I am not buying the argument (from having done large scale systems in both) that OpenAPI is significantly more productive than grpc - especially when building SaaS/control plane services. I do agree tooling is "prettier" for OpenAPI but that is artifact of needing that level of tooling for a spec that to me never felt as expressive to begin with (have to be careful not to get into Yaml vs syntax wars her). On the contrary reading/modifying/consuming grpc specs have never needed a custom UI. OpenAPI is way too tied in the hip with http (doesnt need to be) and a lot of things evolved that way. Grpc never had this problem. As you may have pointed out it needs an extra grpc-gateway plugin to generate a http gateway (which I actually is neat)

+1 on the terrible state of grpc cli tooling (unless you are already working at a faang).

-1 on Web proxy - As mentioned before I actually find that seperating a http "transaltion" gateway from your core biz logic is a win in my mind.

+1 On way too many microservices. IMO whether you use GRPC or OA, you can build monoliths or way too many microservices. I have not felt GRPC explicitly enforced that. What I did get from grpc is the logical seperation with grpc (you can still bundle multiple services in a single binary vs as seperate microservices) if you want. With grpc (nay proto spec) building a service becomes a logical exercise over how do i structure URLs vs what verbs to use etc.

PS: On a completely diff note I actually like your approach to isomorphic types. My switching to the grpc side was largely motivated by this single source of truth from whence all layer specific types came forth from!


The huge thing I love with graphql (and this probably works with OpenAPI as well) is run time mock generation. It makes writing tests a breeze and semi enjoyable.

example: https://www.freecodecamp.org/news/a-new-approach-to-mocking-...


Should graphql ever be used to just cover all the basis of system integration?


Why does OpenAPI appear to be an alternative to REST in your list?


I understand REST APIs more like Hypermedia APIs, where you go to the landing page, it contains links, you follow them, you leverage content types, etc... So by definition, a REST API has no specification, it's an API that the agent can explore.

In contrast, an OpenAPI is a REST-ish API with an OpenAPI specification. It's not as dynamic as REST, it's not Hypermedia, it's much more "JSON over HTTP" but also not exactly RPC.


Building on this...

Look at https://api.github.com/users/octocat

Or the OpenID Connect and /.well-known/openid-configuration https://openid.net/specs/openid-connect-discovery-1_0.html

And while I might be invoking scotsmen, very few things look like https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arc... and so are best described as "REST like" or "RESTish".


But REST is the REST specification. REST doesnt just mean HTTP


I really hate these bland, barely actionable advices with no examples, created for SEO purposes.

Nobody knows how to measure the "complexity" and "evolvability" of the API and where exactly is the threshold that justifies going from REST to GraphQL.

So here's my opinionated alternative:

Use REST everywhere, unless you can justify the exception.

A good exception is when you don't know the audience and use cases for your API. E.g. if you have hundreds of different apps using the same API and you have no idea how they are going to use it. You know who does it? Facebook.

If you're just dogfooding an API for your website, you don't need GraphQL. If you need one service to talk to another, you don't need GraphQL.


> created for SEO purposes

I’ve always thought these posts were for non-technical product buyers and decision makers.


I take not mentioning hypermedia in a post discussing REST as a huge red flag. The author mentions Roy Fielding's dissertation, but apparenly they didn't read it thoroughly.

Furthermore, I believe that a huge confusion comes from not understanding what a "resource" is: it is not a database table*; it is not your domain model*; it is a _representation of state_. Like this very orange page you're looking at. This whole page is the resource identified by https://news.ycombinator.com/item?id=35014395. Just like the stylesheet for this website is a resource identified by https://news.ycombinator.com/news.css.

* It may be, if that's the _representation_ you want.


REST is such a bastardized term. At this point it’s often used synonymously with JSON/HTTP or simply meant to contrast between SOAP, GQL, gRPC, etc. without respect to its actual tenants.


The naming of "resource" is a bit unsettling. From the perspective of the server, it seems natural to think of all databases and external machines. "Representation" sits better with me, but ultimately in the code, I would prefer to name the REST endpoint as a "service".


I like GraphQL because it allows me to describe my API like a domain rather than just a collection of resources. REST is difficult to map to a true domain model because domains aren't just collections of resources. They have nuance. And with GraphQL your API matches your domain, so there's no limit to what your application can accomplish. For example, adding another feature to your front-end no longer requires going back to your API to add a tailored endpoint nearly as often. At worst you're adding a property somewhere that is now available to all your use cases. GraphQL embraces mutations in a way that REST frankly can't without being glorified RPC, and it doesn't have the same perverse incentives such as re-using an endpoint because it exists even though it may be suboptimal.

So, in my opinion, unless your application is very resource/entity-intensive (and you don't mind a little RPC-style bloat) then GraphQL is often a better choice than REST. And if you actually have a rich domain to model (this is the case even for many small applications), then GraphQL is often a better choice than RPC.


Yes, GraphQL allows you to expose a domain. What is a really big problem, because websites are organized as an hierarchy of resources, applications are organized as a collection of actions, and nobody on the user-facing side ever thinks about a domain of small interrelated things.

With nobody thinking about the interface, you are left with the classical dilemma between usability and security. And all GraphQL tooling seems to floor their feet on the usability side.


Thanks, this is thought-provoking. I went and did some reading—-am I mistaken for thinking simply disabling introspection in production is a hard counter to this? I realize for a public API (or API product) that isn’t super helpful, but for my own use cases nobody on production needs it.

Other than that, it seems that the answer is just performing object-level authorization to ensure you never leak resources a user isn’t supposed to have access to. Depending on the framework you use this can be pretty straightforward…


Yes, if your data is not entirely public, you will need object-level autorization.

But the point is that no, it's not straightforward; the authorization must be designed to fit your needs. If you are not designing it, you can be certain that it's broken.


Thanks for taking the time to explain. You’ve helped me revise my opinion (yes, some folks are willing to receive new information and change haha).


I love graphql. It allowed me to scrape a whole bunch of websites with almost no changes to my scraper.


How is this different than a REST API with an open api spec? I suppose GraphQL APIs are just more likely to have introspection turned on since it’s the default?


> with almost no changes to my scraper

Thats the killer feature.


graphql is a data exfiltration engine, it's lovely


I had the pleasure of working with Apollo + GraphQL for the last 2 years and I don’t understand the hype. I haven’t seen anything so over engineered and complex in my whole 20 year long career. To make things worse I quickly found out all the problems GraphQL tries to solve are still there. Like over-fetching is around the corner if you don’t pay attention.

REST on the other hand feels really straightforward, maybe easier to mess up but also much easier to fix. I’d take Redux over Apollo anytime even though Redux is dying according to many.


Well, seems somebody doesn't care about jsonapi/openapi and the rest of the family.

Sparse field sets / compound documents are nothing new and I'd argue its easy to overlook that there's no magic in the backend for graphql either.


I think OP didn't make the distinction between RESt and RESTful APIs. A pity IG you'd ask me


I don't like GraphQL due to the complexity. It's not JSON or YAML, and requires a lot of custom stuff on both ends.

I'd like something like GraphQL, but built on standard data formats.


It hasn't seen much outside adoption, you might enjoy the ideas behind Netflix's Falcor: https://netflix.github.io/falcor/

You can think of it as larger-than-what's-downloaded dynamically-generated JSON object with internal pointers where you can ask to access wanted paths. (Sort of like GraphQL is a larger-than-what's-downloaded dynamically-generated non-JSON object.) One trick they use is that the path segments can also be objects, so `{from: 100, to: 200}` is a valid path segment, and this is how you build fancier query logic with in.

https://youtu.be/hOE6nVVr14c?t=977


Every graphql API I've ever seen returns JSON. It's definitely the standard. What are you referring to?


I think they're referring to the query language itself not being json or yaml


Exactly. It's not just not-JSON, but it's obnoxious and hard to manipulate programmatically, on either end (client or server).

That translates to a lack of tooling around it, an inability to write sane tooling, and difficulty interfacing in higher-order ways to things like interesting data stores. It's designed to be hand-written and parsed only with the official libraries.


GraphQL is extremely useful, if only to have strong type validation between disparate languages, via code generation. It can be a universal typed schema of your data against which you can use whatever server and client combo you want. It's like tRPC but you're not forced to use only TypeScript.

I also have to plug this video [0], since many people think GraphQL somehow is a competitor to SQL and that it goes between the server and the database; it does not and has not ever been intended to be a replacement for a database query language and in fact should never be used there at all. It is only for client/server communication, not server/database communication.

[0] https://www.youtube.com/watch?v=ZfccwYUD8H0


> strong type validation

The limited types in GraphQL kinda make that not very helpful. A RESTful API with JSON Schema or zod schema for it has much stronger types, and you can even make converting to better types be part of the zod schema.


> A RESTful API with JSON Schema

Sure but I get it for free with GraphQL anyway.

> you can even make converting to better types be part of the zod schema

I'm not using TypeScript so this wouldn't be useful to me. That's why I mentioned that GraphQL is good for disparate servers and clients that aren't necessarily just React/Node/TypeScript.


I don't like that GraphQL is called GraphQL.

Its output cannot represent a graph. Its output is finite.

Consider an API that queries people. You query a married person and include their spouse. And then you include the spouse's spouse, and so on.

GraphQL will render as many levels as you request without deduplication.

JSONAPI will do this much better, you'll get 2 entities in 'data', and they'll refer to each other in their relationships block.

Not that I like JSONAPI. Having built larger system with it there is no universal way of supporting pagination in the includes section which makes it a binary proposition about includes. You get ALL the ones you request, or none.


It's a query language for graphs, not a language for transferring graph data.


The main issue that happens with both REST and GraphQL, is that people spend more time thinking of how to implement their thing, than what the API should be.

The complexity GraphQL adds _can_ be worth it for its ability to better represent a business domain via an API. If you don’t care how well your API represents your business domain, then likely your API is going to suck, and you might as well have a sucky REST api and avoid the complexities of GQL.


The article talks about how GraphQL is "flexible" a lot, but I kind of wish they'd spend more words talking about why that matters.

Eg, if you're working on a new product, the odds are very good that your front ends will change pretty rapidly. At the very least, we're way more likely to A/B test application features than we are API schemas, regardless of what methodology or technology our APIs are using.

Because that's why I would pick GraphQL. It's a choice that reduces the barrier to rapid iteration in the clients, but it does add backend and infra work to support it.


> "flexible" a lot, but I kind of wish they'd spend more words talking about why that matters.

I don’t think these articles exist for a technical audience or the bricklayers doing the integration. I think these are for the non-technical decision makers and business executives


Nowhere near a complete guide or even balanced comparison

> GraphQL is a highly flexible option that’s better suited for building APIs that require complex data fetching and manipulation. It deftly avoids over-fetching and under-fetching data, leading to lower bandwidth usage and faster response times.

Yes, but have you tried implementing one? It is not trivial at all to write performance GraphQL backends.

Often, it's a n+1 query you didn't write a batching version for that messes you up.


I have used GraphQL and REST extensively.

I prefer REST. It is easier to cache server side which for certain types of data can be extremely useful. It works well with monitoring software. It is extremely easy to understand with just using curl.

Graphql works extremely well with React. The Graphql Apollo React client fits like a glove and is a pleasure to work with. I have not found a REST library that fits as well although there are likely some now.


Article could be improved by mentioning that the smaller rest requests will have a much higher cache hit ratio when used with HTTP/2.


Everything is higher than zero. GraphQL is inherently not meant to be cached at the transport layer which is why it’s often exposed behind HTTP POST. If caching GraphQL makes sense for your application you probably didn’t need GraphQL in the first place.


The anti GQL circle jerk goes too far. GraphQL is often overkill but it’s awesome if you take advantage of the powers of federation and field specification. If you don’t see a difference between retrieving all fields and just the ones you need then you just haven’t encountered the cases where it makes a difference.


I've been writing flask apps for a while (using sqlalchemy as my ORM) and find myself repeating code all the time when I create GET and POST end points for all my models.

Is there a better, more automatic way to generate GET and POST endpoints automatically when I create a new model?


For JavaScript based projects TeleFunc[1] can make development way simpler by 'removing' the need for an API.

[1]: https://telefunc.com/


> For JavaScript based projects

This is viable for personal projects and things that exist in a vacuum.

Suppose you hit a performance bottleneck with your backend and want to migrate to Go

Or, if you want talk to your JavaScript background from a native mobile client. Or if another team or customer wants access to the API and not using JavaScript.

gRPC solved this problem by having Protobuf as the many-to-many translation layer. Client stubs and backend service stubs in a variety of languages are autogenerated. Telefunc is a subset of this wherein you define the Interface in TypeScript instead of protobuf. With gRPC you also get a binary encoding over the wire. Maybe the effort of the project could have been building on top of gRPC (which is not necessarily coupled to protobuf) and adding automatic codegen tooling for JavaScript.


There seem to be a lot of people pushing back on GraphQL who often don't seem to understand what it really is, or what it can do. They often seem to think that it's super complicated to build and use, and that REST(-ish) APIs are somehow magically simpler and easier.

Are RESTish APIs simple to build? I mean, yeah. You can have a server running serving an endpoint in like a minute in most programming languages. But FWIW, this also applies to GQL. Take a gander at any GQL resolver tutorial. But is that really what makes it simple?

When you build APIs, they aren't made to exist in isolation. They're made to be consumed. Ideally, they should be easy to consume, which can mean a lot of things.. but "it's easy to send an HTTP request" is not one of those things.

They're easy to consume if they are documented and come with schemas. They are easy to consume if there is tooling to generate fully typed clients for them. Arguably, OpenAPI schemas could fit this description, but in my experience, OAPI support is really varied, both on the server and for clients. Generated clients tend to be lots of code and incredibly clunky. Support server-side is heavily reliant on the server libraries being capable of exposing schemas in some way. In some languages this is trivial, but in e.g. javascript or typescript, you will need some way to expose your types. Just having typescript interfaces isn't enough(without extra tooling or reflection).

GraphQL is typed by definition. The schema is the API, and the types, and the documentation. We have great tooling to generate code in any language, and code-first resolver libraries(like the excellent pothos-graphql.dev) make building your schema along with your resolvers an absolute joy.

Then there's things like the N+1 problem. RESTish APIs are sort of "procedural". Each endpoint is usually a resource, and if you want to fetch a resource and its related resources, you will often have to fetch it and them separately. You can also embed them in the resource, or you can resort to all sorts of not-very-standardized methods of conditionally expanding relationships to do it, which is already just sort of doing what GQL does, except much worse(and is I think not supported in OpenAPI at all?). In GQL, you can also run into N+1, but modern libraries make this super easy to solve. Either they can tightly integrate with something like the underlying ORM, or you can write dataloaders for your types, so that every time a specific resource is requested en-masse, it is always loaded efficiently. Not so much for REST, unless you apply very careful engineering and design.

GraphQL just makes all these things such a breeze. There are some things you need to think about, of course. Query complexity is one thing; you don't want someone to bring down your server using 30-level nested query. Thankfully, people have been using GQL for years at this point and most of these problems are solved, and many of them incredibly neatly.


REST is basically a subset of GraphQL.


From a caching perspective REST is a superset IMHO.


There's a lot to caching that REST gets wrong. It thinks in terms of URLs being cacheable, but that's very limiting. GraphQL caches at the level of the objects in the response. Almost every REST API will return multiple objects from one URL. With GraphQL, newer data coming in from query2 can update components showing data from query1 if they both reference the same object even if query2 is a different URL. REST just doesn't have those smarts. Yes, a HTTP DELETE request will clear the cache for a particular URL, and there's no equivalent in GraphQL, (that I know of) but I don't think I've ever been able to take advantage of that in real life.

At the network level, GraphQL can automatically set cache headers depending on the content. REST doesn't know what you're sending, so it's up to you to know that when you start sending mixed data (to save clients a roundtrip), the cache header may be impacted. https://www.apollographql.com/docs/apollo-server/performance...

On the client-side, caching with GraphQL is far ahead of dealing with a REST API. It knows more about what data it has in cache so it's better able to automatically avoid network requests. Further, a cache-and-network fetch policy is just another parameter for your query and the plumbing for that is handled transparently.


Just like OOP vs FP. REST is OOP (you start with resource), Graphql deals with function (query and mutation).


I'm not following how shifting the resource definition from server-side to client-side makes it any more "FP" than REST.


Where does tRPC, where you start with types, fit in?


Yeah, it would be like dynamic type vs static type.


imma let u finish, but a hypermedia is a necessary constraint for an API to be RESTful...

edit: more usefully, you need to be really careful w/ your GraphQL end points because they are being access in an untrusted computing environment:

https://intercoolerjs.org/2016/02/17/api-churn-vs-security.h...

my understanding is that facebook whitelists their graphql queries but, last I looked, I didn't see security getting much attention around it...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: