77 comments

[ 5.6 ms ] story [ 163 ms ] thread
If you know ThePrimeagen on Twitter/YouTube, he worked on Falcor (the precursor to this GraphQL change) and he talks more about it [0].

GraphQL is very useful, it removes whole classes of bugs. You can even use a Result/Either type where if you don't handle both the success and error cases, the GraphQL request won't even compile, so you can get type safety at both the client and the server while also not having to use purely TypeScript like with tRPC, allowing multiple clients like mobile and web. Pothos does this very well as an error extension [1], where, given the schema:

    type Error {
      message: String!
    }
    
    type Query {
      hello(name: String!): QueryHelloResult
    }
    
    union QueryHelloResult = Error | QueryHelloSuccess
    
    type QueryHelloSuccess {
      data: String!
    }
you can then query it with

    query {
      hello(name: "World") {
        __typename
        ... on Error {
          message
        }
        ... on QueryHelloSuccess {
          data
        }
      }
    } 
If you forget `... on Error` the query will simply fail.

I should also add that most people use GraphQL incorrectly, to get the benefits of not over/underfetching, the Relay approach using fragments is the only viable way currently. Otherwise it's not too much better than REST. You define the exact data required for a specific React component in GraphQL fragments, then the Relay compiler will stitch those fragments together into one and only one request. This is a great (if long) overview on the problems Relay solves and why everyone else uses GraphQL incorrectly (then complain that GraphQL sucks) [2]. Hint, Apollo is not the way.

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

[1] https://pothos-graphql.dev/docs/plugins/errors

[2] https://alan.norbauer.com/articles/relay-style-graphql

> Otherwise it's not too much better than REST

Not sure how much on the "better" scale it counts but the server introspection with tools like GraphiQL is one of the highlights of working with GraphQL for me I don't get with other systems.

Indeed, I use tools like GraphiQL all the time too, although it's not too much different than Postman for REST I suppose. But yes, being able to see all valid types and configurations of the schema as well.

FYI, GraphiQL is deprecated, GraphQL Playground is a good alternative.

> everyone else uses GraphQL incorrectly

Quite a hot take but I can't disagree. I was one of the people using GraphQL incorrectly for the longest time. I always knew something was off, that we might as well have just been using rest, but could never really articulate it.

Alan's article is a great read, thanks for sharing.

Indeed, I used to use Apollo for quite a while and started asking myself why I was doing this to myself, the benefits didn't seem that clear. But someone mentioned to me on /r/GraphQL about how Relay is the correct way, as Facebook initially envisioned, and once I learned it, I was hooked.

Sadly, Relay usage is 1/100 the size of Apollo, even though it is literally the way GraphQL was meant to be used, so I try to talk about it wherever I can. It really is such a simple concept (list out all of the data that you need for a given part of the app, then let the compiler manage these dependencies) that is only now starting to be used in other areas, such as the GraphQL Codegen tool: https://the-guild.dev/blog/unleash-the-power-of-fragments-wi.... It's still more incomplete and not as powerful but hopefully we can start integrating fragment stitching into the mainline GraphQL entities so that everyone benefits from this approach.

It really reminds me of Vim, it started off being one of the best ways to write, and now 20 years later we have other editors reinventing the wheel to get closer to the Vim philosophy.

What are the main headaches and downsides of the apollo method? i was just at this fork in the road on something i was working on
I just replied to your other comment but definitely check out the article I mentioned: https://alan.norbauer.com/articles/relay-style-graphql

It's not so much downsides of Apollo, more so that it could be done better. Apollo does have things like the n+1 problem which are not present in Relay, so that could be considered a headache as it's annoying to solve if not using Relay.

Interesting at "apollo is not the way" can you expand more on that? im using vue with a new app im building. we proved our business idea with a 3rd party platform and im now building my own with 1 other person. I wanted to use graphql so I can make our nuxt3 app have leaner requests, and i wouldnt have to always bug the other guy to add endpoints. it was more of just an idea though, not something i have really seriously researched or considered
The article I linked has much more information on the concept but essentially Apollo and most other GraphQL clients/servers don't do fragment stitching. Imagine laying out the data dependencies for each of your Vue components and having the frontend automatically refetch or cache invalidate whenever the data changes, with no input on your part. You would thus never over or underfetch your data, you get exactly the data you need at any part of your application. This is what Relay does.

Relay is for React only however since Facebook made all of these technologies. I recommend using React and NextJS if you can, I used to use Vue but found that the ecosystem for non-React frameworks was still worse than React, so I switched.

Thanks for the great comment. I often see GraphQL get a bad rap in comments on this site but most of the time it seems to come from a misunderstanding of how to use it.
All of this is possible with a jsonschema too.

I agree that most people use GraphQL wrong because its impossible to use 'right'.

Graphql 'solves' the trivial while hinting towards a future of self-describing apis and anything in between. Users will hopefully find out that GraphQL never solved any actual problems. Actual problems(valdation, (actual)error-handing, cache-invalidation being the big one in the end like usual) are kept for the user as an exercise, like always. Their promises are always not explicit but implied so the tech-enthusiasts can pick it up.

I remember an article here that was talking about how GraphQL would enable apis to discover eachother on the whole internet and learn to speak to eachother without human intervention.

The main selling point in the beginning was so you don't have to query fields you don't actually need to keep data transfer to a minimum. A completely trivial feature for a json api.

Even a JSON api with relations is just as possible and just as easy with a JSON api. Unlike GraphQL you don't have to pretend syntax was the issue.

> Actual problems(valdation, (actual)error-handing, cache-invalidation being the big one in the end like usual) are kept for the user as an exercise, like always

As I mentioned elsewhere, Relay solves all of these problems automatically while people try to hack around their homegrown solution with React Query and the like. JSON Schema is tacked on as an afterthought to REST, not built in, so it's necessarily more hacky than REST.

Yes, Relay does a good job at many of these problems.

Graphql SHOULD have been Relay.

Graphql without Relay is almost just a syntax.

True, I will agree with you on that, and I mean, Facebook uses GraphQL just as they intended it with Relay, what are they supposed to do if others just use it as a syntax instead?
Textbook example of a proper TDD practice at scale. You change the left but not the right. Clean that up and make sure it’s robust. Then change the right. Test, then test some more. Obviously novel at Netflix scale but still. The practices at the service extend to the architecture and everyone’s a winner.

Good work and great write up.

Why did they migrate to GraphQL to begin with? Seems like the applications were using a REST API, what caused them to move?
I cant speak to Netflix's reasons, but one thing you get with GraphQL is a strongly-typed interface. REST has Swagger/OpenAPI, but it was tacked on as an afterthought and the tooling is often second-rate compared to GraphQL (which often allows you to make use of codegen).

Strongly Schema'd interfaces makes client development go faster and smoother in general.

It's all JSON typically, I don't think you can really compare the two that way. They're both just contracts that you hope are respected.
> Strongly Schema'd interfaces makes client development go faster and smoother in general.

What trade-offs exist for strongly typed schemas? It reminds me of indexing database inserts, longer to write and faster to subsequently query. I would argue strong schemas require more design and architectural discipline during constructions and are thus easier to consume down the line.

To quote Bay Area rapper G-eazy "everything costs something bro"

Couldn't that be dealt with by improving the tooling dev teams are using? I'm assuming a migration like the one described here are a huge effort.
yes. If GraphQL is anything it's absolutely batteries not included.

When people speak of tooling they are almost certainly talking about Apollo. I think you could probably find a similar analog in the SOAP XML days. There were lots of vendors, lots of tooling, and mostly the same challenges and outcomes. It could be as nice as you wanted if you spent the time and effort getting there.

To make this more concrete, GraphQL is "strongly typed" in the sense that you get a run-time error when you use the types incorrectly. That's fine for development. Not so much for production. In order to get end-to-end typing you need to integrate with TypeScript or whatever language you're using. That has its own set of challenges. Your build process needs to know which GraphQL endpoint to use (not so easy when doing development on the API or need to use staging environments, etc.) and then generate typings based on that.

Errors are another GraphQL travesty. Do you use out-of-band HTTP errors? In-band error codes? Both? (ugh, but probably once more than 1 developer touches the code). Do those errors kill your entire query? What or who determines that?

I could also mention caching. But that's enough headaches for today. You need tooling just to get up to bog standard HTTP and browser caching gives you for free.

You can get compile time typing too, if you use GraphQL's unions. I wrote an example in my other comment: https://news.ycombinator.com/item?id=37125685

If unions are used for errors as well, you essentially have the Result/Either type inside GraphQL at compile time. This is much stronger than anything REST provides.

Postgraphile https://postgraphile.org/

Hasura https://hasura.io/

Examples of "batteries included" GraphQL. Combine with a type generator for the language of your choice (eg. https://the-guild.dev/graphql/codegen), and you've got your client interface to avoid any type errors. Each comes with a GraphiQL UI for access out of the box as well. It's more turnkey than any REST solutions I've seen, that's for sure.

For different environments, it's quite possible (even normal?) to generate your types and GraphQL schema ahead of time, before CI/CD build of the UI to catch errors early at compile time.

Now add in SvelteKit with KitQL (https://www.kitql.dev/), and you've got a very simple, flexible, and efficient end-to-end solution.

As for errors, because each resolver can generate errors and not all errors are considered fatal, the errors must necessarily be embedded with the response and treated by the network client as they see fit. It's definitely different from REST, but not inferior. It's a different set of tradeoffs. When using a schema generator like Postgraphile or Hasura, it's unlikely you'd get errors in practice. The endpoints are basically guaranteed to resolve, and the generated SQL is nigh certain to execute correctly. If you get one error, chances are the whole endpoint is down due to a database connectivity problem. (That has been my experience at any rate.)

Don't take my word for it. Bring up a Postgres database, put some data in, and point one of these tools at it. I think you'll be pleasantly surprised. You may still prefer REST (or gRPC), but I think we can both agree that "batteries included" is definitely an option with GraphQL.

What do you mean with an afterthought and second rated? Maybe you mean that it's not defined in the "protocol" itself, REST is not really much of a protocol anyway, but rather a set of guidelines on how to use HTTP sanely to make a CRUD API. You can still have all your REST API's from your application follow a certain agreed on "REST protocol". If you use a framework / library for making the API then usually you don't really have to think about that (much).
It says in the article that they weren’t migrating from REST. They had an internally-developed technology that’s very similar to GraphQL called Falcor that they’ve been using. They actually had it before GraphQL was a thing, but futzed around with getting it released to the public during which time GraphQL took over in that niche. So now they’re streamlining and going with the commodity tech.
In a place that I worked was simply the over fetching nature of RESTFul.

...

Organizationally speaking, I've worked in a company that an interesting approach to federated teams: All the backend applications would have an GraphQL endpoint that would connect to a middleware where all front-end would consume the data.

This allowed not only to avoid that over fetching, but different applications with different data needs could cross fetch the data via GraphQL and resolve them and display it in their own front-end.

Took a lot of work to reach a level of maturity but was the best place that I've worked in terms of federated services/backends serving multiple front-ends.

    Until recently, an internal API framework, Falcor,
    powered our mobile apps. They are now backed by
    Federated GraphQL, a distributed approach to APIs
    where domain teams can independently manage and
    own specific sections of the API.
I was an early-adopter of Falcor back when Netflix first started promoting it, and have also spent some time migrating those Falcor calls to GraphQL.
I’m sceptical that migrating to GraphQL is actually an improvement. Instead of one team maintaining a cohesive API, you now have unlimited teams making shit up as they go?

The article also desperately needs more context. I don’t doubt a lot of cool engineering went into making this work, but for an outsider reading the article (and without them stating any goals apart from velocity) it’s unclear whether the whole thing was just an expensive resume driven development or an actual necessity that justified the invested engineering time

I posted this in another comment but if you know ThePrimeagen on Twitter/YouTube, he worked on Falcor (the precursor to this GraphQL change) and he talks more about it: https://www.youtube.com/watch?v=yab6i9lrEv0. TLDR, monolith made it hard for them to continue adding features.
I personally love GraphQL but my god is that man annoying
The first 0.2 seconds of that video made me doubt ever using GraphQL again.
Why do people do this, I think surely they don't behave this way in real life, but they feel the need to for YouTube?

Another example that comes to mind, one I actually bared to watch some of, is Stephen Hawes (née Stephen the Robot). Great content, obviously a smart guy doing some great stuff. But every video starts over-excited 'hello my goblins and ghouls' (what?), we get crash zooms in on his face and mouth, violent music and head jerks to mark scene transitions, etc.

Of course by all means have some personality, it's your video, etc., I just don't believe this is their (offline) personality?

Matthias Wandel, Clough42, Marius Hornberger, and Phil's Lab I think each clearly have a certain personality that comes through, but it's 'professional', it's truly them, I assume, I think if I knew or met or worked with them in real life that they'd be exactly as I 'know' them to be. They seem genuine, and not insane.

Use SponsorBlock to skip all of that filler, it skips more than just sponsors if you set it to do so in the settings.
Idk, last time I watched YouTube a lot was about a decade ago. It doesn't seem fun anymore.
Does using Graphql inherently solve the monolith problem, or is adapting GraphQL just a biproduct of looking for a federated system?
Seems to be the latter. I imagine they could have used gRPC as well but I definitely like the one-schema nature of GraphQL.
I have not really figured out whether it's worse to turn programmers into API designers, or to force programmers to talk to each other and agree on a schedule for a feature that only benefits one half of the people talking to each other. Both are tricky.

To me, I think backend teams largely want to be left alone, while frontend teams want to make Their Thing today. So the backend teams say "sure we'll make an API" and then the frontend teams in theory never schedule PM-driven meetings with them, but can still experiment with new interaction patterns cheaply.

How this all works out in practice, I'm unsure, but highly suspicious. My personal opinion is that frontend and backend developers working on the same codebase, going to the same meetings, reviewing each other's code is probably faster and more efficient in the long run. But at some point you need 100 teams, and the "just have one team" method can't scale, so at that point, you have to accept that you can't be perfect and come up with something. GraphQL is that something.

(I would have just used SQL. Many good libraries around for parsing them into query plans that are easy to execute.)

I don’t get Graphql … what does it add, what’s better with graphql?
My understanding is that it’s the preferred way for a lot of frontend engineers to build their experiences. It gives a lot of freedom and reduces entire classes of bugs due to the type system.

Edit: to elaborate; “a lot of freedom” means an entire schema instead of pre-negotiated contracts, potentially reducing back and forth between frontend and backend.

Yep. Imagine an api scheme that matches the underlying normalized database structures. In order to render a view, you may need dozens of calls to different services to gather all of the data you need. Some places have been moving towards backend for front end (BFF) as a way of providing a better abstraction layer for UI development and some have been exploring GraphQL where the data can be combined and aggregated within call as dictated by the front end. I will say that the time I’ve spent working on front ends with a good graphql implementation were much more efficient and reduced overhead of dealing with more typical API interfaces.

This isn’t something I’d rush into though. There is real overhead in managing graphql and in my opinion is best suited for extremely large API spaces that most companies simply don’t have to deal with. Microsoft and their graphql implementation is one where I see it as a better option than hundreds if not thousands of different services with different endpoints.

https://developer.microsoft.com/en-us/graph/graph-explorer

GraphQL makes sense when you have:

  - Many teams with many micorservices with many underlying stores
  - A fetch-based architecture
Each team can be responsible for implementing the resolver for their service along with caching, scaling, etc. At Netflix's scale you don't want to have every single service have to scale to the level of the BFF/Orchestration layer. https://www.apollographql.com/docs/apollo-server/data/resolv...

If you have push-based architecture, it makes more sense for underlying microservices to publish to a broker like Kafka and then materialize a view to DynamoDB, Mongo, Redis, etc.

And if you don't have many teams with many microservices, then just do the REST, Rails, MVC thing and save yourself the headache.

Thanks for the explanation. I guess the overhead does make sense at a certain scale. The unfortunate thing is that articles like this always end up inspiring some bored engineer/CTO to redesign everything so it is "webscale" like Netflix and blow the mid/small-sized companies' Christmas bonus on AWS bills.
End to end type safety that's better than REST and even stronger than others like gRPC by using the Result type, see my comment for an example: https://news.ycombinator.com/item?id=37125685

An endpoint that fetches exactly the data it needs for an entire application, never over or underfetching.

Independence between the frontend and the backend, as the backend can implement resolvers for a certain piece of data and the frontend can then query anything that contains that data without waiting for the backend to implement a specific endpoint with that data.

Seriously, GraphQL (when used correctly with Relay, rather than Apollo) is among the best developer experiences I've ever had.

The sibling comments here are weird to me. IME the primary reason to us GraphQL is explicitly solve the dilemma of "ReST-ful" endpoints:

1) An endpoint returns a superset of the data any client may need, which means more data is loaded than any given client needs (which means wasted bandwidth/compute)

2) An endpoint returns a subset of the data all clients need, which means any given client has to tack on additional queries to get everything it needs (which means more roundtrips)

(There's the third option of tacking on "includes" or "excludes" parameters to endpoints, but at that point you're evolving an ad hoc, informally-specified, bug-ridden implementation of half of GraphQL, to massacre Greenspun's tenth rule).

How important solving this dilemma is to your application may be a function of your team or system topology, and the type safety that GraphQL happens to come with is a nice bonus, but this dilemma is the crux of things.

GraphQL is another one of those "perfect technical solutions" that ends up being annoying as hell. Basically, managing multiple different endpoints is complicated, so they wanted to make one interface for multiple endpoints. But that one interface is now complicated, whereas before each of the multiple different endpoints was simple.

I would suggest avoiding it until you're certain you need it, and consider how annoying it might be for the user. (Don't make me learn a language, then syntax check it, just to ask your API to give me some basic info)

It’s clearly one of those tools meant for big teams with big scale problems.
I disagree; in my experience, it’s really great for small teams with fewer full-stack engineers. More specialized frontend engineers can rapidly iterate and prototype interfaces without needing to make corresponding API changes to endpoints, nor requesting massive payloads with a bunch of frontloaded crap.

But also in my experience it’s better to go all-in on either REST or GQL; supporting both is a time suck.

I've been down the route where GraphQL eventually becomes important after months of trying to avoid it, specifically as the main gateway for a frontend to fetch stuff. Good news is you don't have to start with it for that use case, you can add it on when it starts making sense. You sacrifice a little performance and have a small mess in the meantime, not a game-changer, so I can see the YAGNI argument. But I might start with GQL from square 1 next time.

For public APIs, you have to choose further in advance whether or not to use it. Never been in that situation myself, but I'd be on the fence because I agree it's annoying for the user.

What made GraphQL become important?
We had a NodeJS backend and an iPhone/Android app frontend communicating over JSON-over-HTTP with an OpenAPI spec. It was a social-like app with endpoints like /getUsers, /getPost, /makePost, whatever. There were lots of cross-references, such as a post having the posting user, and we were just sending IDs from the backend so the frontend could look up the referenced objects on its own. The idea was the frontend would cache things, avoiding tons of lookups. This is probably what a backend-backend interaction would look like, but it wasn't suitable for frontend.

Frontend dev team didn't want to own this much logic and started asking for nested objects in the API, usually with only a few fields. Like they needed the poster's handle and avatar for each post, and they'd only request more detail when visiting the profile. So we started cramming it all in there. A bit wasteful and tedious, not the end of the world, but GraphQL would have been a much more elegant solution.

Also, frontend and backend teams were on opposite sides of the world. If backend team added a new endpoint but missed something the frontend needed, it'd be a full day before they heard back. So it was best to err on the side of sending too much info back then remove parts of it later.

This is a good example of why planning is important. The front end team should have stubbed out the backend, iterated as they liked, and told the backend team we need these requests for these pages

Graphql is popular in part due to communication dysfunction.

They did some stubbing as needed, but that doesn't change how it's still messy and tedious for the backend team to support so many different combinations of data instead of just handing them a GQL.

Also, to be frank, frontend team was paid a lot less per head than backend team. Their expertise was just in building the UI according to what the backend team and designers gave them, and they were very good at that. Stubbing wasn't an efficient use of their time.

I'd love to know more about how better planning could have made GraphQL not so useful here.

I think I've encountered the same (or a similar) issue when the front-end needs some data that conditionally relates several objects in your data model. None of your openAPI endpoints cleanly map to the "bag of data" you need, but you can have the server bolt on additional data from other models in response to certain types of requests, and the front-end can construct its components based on that. However, this gets ugly.

The alternatives, as I see it, are to have the frontend make multiple requests, sometimes in sequence, and then compose the data it needs from the separate responses, or to altogether abandon REST for a JSON RPC (something like tRPC might really shine here).

Or to use GraphQL, which simplifies things greatly as the frontend can now request the data it needs in the structure it needs it, and Apollo server or whatever you have on the backend can service those requests and plan the optimal path to fetch and transform the data.

Caveat, I've never actually implemented this pattern on a backend, it's just something I've considered after running into the above issues, so I admit I could just be misunderstanding how GraphQL can be useful in this problem space.

But I'm curious if there are other patterns for this problem that, as I believe you were suggesting, could eliminate the problem without adding GraphQL into the mix

If you're in the business of always designing a new backend API for every new service or page, then yeah, backend needs to be at the table from the beginning and the backend API can accommodate the design. Part of the point of frameworks like GraphQL, though, is that it lets your backend avoid that kind of churn. A feature attached to a node becomes usable by every authorized call that references that node, not just the specific endpoint they it was implemented for.
Exactly. You don't need GQL to alleviate this, but in hindsight it would've been worth the cost.
What would you recommend as an alternative?

I have been using json-api but unfortunately the only good server-side impl I found was graphiti.dev (ruby).

Are there other recommendations?

I wouldn't use GraphQL for an external API, it's best for internal data sharing in a type safe way between the frontend and backend.
It’s difficult to migrate away from. How do you know what you can stop if you don’t know what the exact requirements of client are?

I think it’s a stupid thing to deploy

This article seems to be missing the What and Why, and is only describing the How.
So they moved to GraphQL to get type safety but the implementation of this posed a major risk. I would have liked to be in the room for that decision making.
Great post, really enjoyed the breakdown and approach taken.
Curious why there didn’t seem to be consideration for grpc, but I suppose this is the how, not why. But still, not even recalling why and alternatives considered?

IMHO the strict contract that grpc makes sense if the tooling and language support can catch up.

Want to give a shout out to an alternative to Apollo, which is GraphQL Yoga[0]

It tends to support the latest accepted RFCs of the GraphQL spec, works with subscriptions, can do a form of federation via Schema Stitching[1] and is a blast to work with.

The company behind it (The Guild) also has a service called Hive[2] that can provide analytics, schema checks, manage gateways etc.

For complex cases, they also have GraphQL Mesh[3] as an alternative to Apollo Gateway

[0]: https://the-guild.dev/graphql/yoga-server/docs

[1]: https://the-guild.dev/graphql/stitching/docs

[2]: https://the-guild.dev/graphql/hive

[3]: https://the-guild.dev/graphql/mesh

(comment deleted)
++ on the Guild. They are leaders in the GraphQL tooling space and offer a wide array of solutions.

I'd also like to give a nod to Wundergraph and their Apollo Alternative.

We were given early access to Cosmo[0] and so far are very happy with it.

They have their own GoLang based router that is independent of Apollo, works with v1 and v2 of federation, and works with subscriptions.

Comes with Studio, a CLI tool, and a OTEL Collector. So far it's been great for us at our org.

[0]: https://wundergraph.com/cosmo