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