The main issue of GraphQL is awful tooling, especially outside of the js.
For example, we have done small rewrite of Apollo Android library and achieved like 100x performance boost simply by writing as it should be written. Literally very minor changes and better DB.
Typesafe codegeneration? Still feels very beta anything your could find.
Compare it to something like grpc that have strict typed clients for almost anything.
100% this! Outside of JS, the tooling seems non existent.
What's so amazing to me is that it is really easy to spin up a server that talks graphql in any language. But there is no client support.
And hand crafting queries is a million times worse than reading the rest documents
Oh, you want to get a list of items by owner, you can do that but you'll also have to paginated the inside and outside list. And the client will have to follow these pages while also having a deep understanding of your model.
Without good client tooling, graphql is a nightmare.
What kind of client side support do you need? You send a query document in a POST and get JSON back. I'm pretty sure all languages have an http client and a json library.
How is pagination worse than the REST equivalent?
I guess I could see a case for client side caching based on IDs, but unless you couple this with subscriptions thats kind of brittle.
The main different on pagination, is that you pages return inside an object. And you have have several different objects that all have different pages.
With rest, you can only paginate that particular call. You cannot really paginate different results in that one call. At most you can do is say get the list of objects at this endpoint. And that is far easier to grok than graphql's pagination in even the simple case.
I think this is the important point here; it’s not hard to call GraphQL and even create a client starting from copying @urql/core for instance, but I suppose at some point if you want the same benefits on your other platforms normalized caching will be of interest, which means it isn’t as trivial to get to feature parity. So I think it’s still a valid point
It's easy to spin up a server. Spinning up a server that can actually access your data in a way that has reasonable performance is another matter entirely.
With WunderGraph I actually want to go the other way around. Instead of having a "smart" GraphQL client I let users write their Queries/Mutations/Subscriptions in GraphiQL. I'll then take the operations and generate a fully typesafe "dumb" client which has no clue about GraphQL at all. The Operation gets persisted as an RPC which the dumb client can then call. Feels like GraphQL, behaves like GraphQL but is very lightweight, performant and secure at the same time. All it takes is one code generation step but I think that's acceptable. GRPC does it the same way.
I would argue that even in JS the tooling is bad compared to other options. If you can't get autocomplete, strict types, etc out of the box without backflips, it isn't really worth whatever other benefits you may be getting.
This was a big reason we decided not to release a GraphQL version of our REST API at my previous employer. Most backend languages have poor gql clients, if any at all.
Better to just provide a nice, typesafe client library generated from OAS.
We are using hasura (which is written in Haskel), I'm interested in dgraph.io (which is golang).
I had terrible experience writing graphql-service in typescript. I finished it but I did not liked it's strange behaviour and bloated docker image size.
I rewrote it in 2 days with graphql-go/go and then it became OK: predictable behaviour and ~16Mb docker image.
I'm thinking about rewriting another service too.
On client side I used:
- python client `gql`
- .NET `graphql-dotnet`
- Apollo client
- graphqurl - js client from hasura team
The worst impressions are from Apollo.
Starting from their documentation.
IDK why they explain everything starting from UI.
If you’re after raw speed I can see this but it’s near impossible for a human to parse and requires a spec to implement a client which means it picks up what I personally feel are the worst parts of the other available options with only one benefit. Some use cases make the speed alone worth it, but like graph I don’t think gRPC is as generally useful as the alternatives.
gRPC is coupled to individual services whereas graphql gives you an abstraction layer that allows you to expose your data in a controlled manner while allowing you the flexibility to refactor the underlying services whenever you want.
Because GraphQL is difficult to explore. I want to write code without knowing anything about your API before I start. That said, I absolutely understand the appeal if you're writing the client and the server, and don't care about your API users.
Edit: Since I got a bunch of questions that seemed to be the same. The few times I've used a graphQL API i was expected to know which attributes I was requesting per object, instead of just getting them all and figuring it out later. That was my main concern. I want to find an endpoint, get a list of objects without knowing what will be in them and start throwing stuff at it. I usually do this in python using jupyter, so when I'm finished exploring I have working code that just needs to be refactored a bit to fit into wherever it's going to go.
For me, this workflow is usually faster than even finding the documentation on most systems.
But yeah i apologize for my early morning crankiness, I was really complaining about a few specific implementations of GraphQL that I found frustrating. And to be fair these specific companies I'm thinking about also had annoying REST/SOAP APIs in the past and are now touting GraphQL as a sort of silver bullet.
? Implementations I've seen have the ability to show schema & documentation that you can explore via the client side. GraphQL Playground for running queries, etc.
I have no clue where you're coming from. Graphql is fully explorable by design, its in the actual spec. This actually solves a true problem with rest apis, half assed, outdated docs.
Graphql coupled with graphiql is extremely easy to explore. So easy in fact that we have replaced all of our api documentation with graphiql instances that we provide to our clients.
I would encourage you to learn more about the tooling before posting FUD.
Sure. but I said I want to start writing code before I know anything about the API. I don't want to have to install some tool, figure out how to configure it, then look through the API, and convert what I find into code. I want to start coding, and explore using the code I'm writing as I write it.
In theory I would agree, but most of the time I need to have a special account with the vendor to see the docs, and the docs are never up to date, even when they're dynamically generated somehow. Plus I'm not always using an API that expects me to be using it. Sometimes the API goes out of it's way to prevent me from using it, but the vendor gives me their blessing to try.
Interacting with systems like this for a decade has conditioned me to just try it out first, and then look up what i need to know if i'm having trouble, or need to optimize.
What else are you doing with Jupyter notebooks, if you don't mind me asking? What's been your experience, your frustrations, and moments of delight?
We built a machine learning platform[0] with additional functionality [near real-time collaboration, long-running notebook scheduling, automatic model tracking and deployment, etc.]
I don't think this will help your product directly, but I mostly use jupyter as a better repl that lets me figure things out for a one off, or to have something to copy and paste into wherever it's going to live.
It's really good for tab completing a new library I'm trying, especially if said library dynamically creates attributes with their own dynamic attributes.
I was doing that in ipython before the notebook was released, but what really won me over in the notebook was parsing data that didn't want to be parsed. I could have different cells that set a blob of data to different states, and try tweaking regexes or splits or whatever without having to restart or save intermediate files. And if I mess something up I just rerun the appropriate cells to get me back to where I was.
My biggest complaint is the way it handles automatic parentheses and quotes, it's just always a bit off.
Thank you for your input. If you happen to be on a machine that doesn't have your usual setup, please consider using our platform. It's super useful if you work with other people remotely as you're able to work on the same notebook in near real-time[0], see each other's cursors and changes, etc.
[0]: I've received some remarks about the fact I say "near real-time" and not "real-time". We have too many people from an Electronics Engineering background, including myself, on the team to dare use the term "real-time" for a web service. That's why we say "near real-time".
The difficulty caching responses between client and server can’t be helping its cause either, nor the relatively immature state of the tooling around graph. I do feel it has some interesting advantages with selective queries and such but at the moment I still don’t think it’s ready for prime time.
I think even the name overstates its capabilities. Compared to something like sparql it is a comically limited language only suited for front end syntax sugar, which is fine. But let’s not pretend that it’s going to change the world in a Michael Jackson sorta way.
With GraphQL and single page apps, people tend to move their business logic to the frontend side. I am not sure it is a good idea seeing how moving are the frontend tech
Interesting observation, because my own experience has been the opposite. With GraphQL I've been able to more easily push business logic to the server.
My experience have also been the opposite. With GraphQL I can normalize queries and mutations the way it is more fit to the frontend and de-normalize/re-normalize it in the backend.
For me GraphQL is the epitome (in the Web tier) of 'we need to solve the same problems as FAANG does'.
You'll likely never be in a situation where over-querying via a non-granular REST call will ever be an issue worth optimising around.
If you're shipping multi-megs of JS to a client don't then pretend that micro-optimisating the API call waterfall is your KPI, it's just disingenuous at best.
At best it's a band-aid around dysfunctional inter-team working.
You say band aid, I say that it can be a great catalyst to "leave past, bad practices behind". Don't discount the psychological effect of switching to a new paradigm. It can truly empower people to feel that they can "do it right".
I'm not saying it's enough, far from it. Bit it can be a very liberating 1st step.
I dont disagree with this, but I also see in our case that good tooling is immensely valuable in keeping things consistent and moving forward (in the same direction) without having to discuss every change.
> You'll likely never be in a situation where over-querying via a non-granular REST call will ever be an issue worth optimising around.
While I agree with your beginning sentence, the one I quoted doesn't sit well with me. It would be good to remember that not everybody has 100 Mbits fiber or 5G download speed.
We all saw the data on how milliseconds affect user retention then proceed to completely forget about it once building our apps.
Even if users don’t have 5G, why is your rest api so slow that it’s an issue? Why is graphql the solution? The featured article points out that optimising rest can be a better solution, in terms of time and effort, than implementing graphql. The problem that graphql solves isn’t this one.
GraphQL also allows the frontend team to iterate faster, because they don't need to ask the API team to change an endpoint, or add one. The API team also moves faster, they define the relationships and they are done, no going back and updating endpoints.
GraphQL creates a data graph that powers the UI, REST creates a database that you can query on the UI and you have to compose it all together and manage.
What if you don’t have separate teams, or what if your teams are in the same room? Why do you want your frontend to select it’s own data rather than consuming predefined known quantities? Is this not analogous to type safety? Is graphql not in fact closer to having a database that you query from the frontend, not least of all because it literally has ‘query language’ in the name?
At my last place the "product" team owned the clients (website, app) and the GraphQL layer, and the "platform" team owned the business logic just beneath the GraphQL layer (it happened to be in monolith though, so the boundaries between teams were intentionally fuzzy).
> What if you don’t have separate teams, or what if your teams are in the same room? Why do you want your frontend to select it’s own data rather than consuming predefined known quantities?
Then you don't share many of the reasons GraphQL was originally created for. Act accordingly.
Another way to put that is to say that GraphQL is just a way to ship your raw DB schema as JSON. I thought we learned it was bad to shape your front-end code to the mirror the DB schema, sometime back in the early dot-com era.
But the entities, names, dates, and photo URLs in my database are exactly what I want to show on the frontend, by and large. Maybe a join, aggregation, or something in there.
Right, but now when you are deciding on a schema change, your front ends clients are going to break because you didn’t create an API, the just allowed db querying from the front end.
Web API contracts are primarily routes and request/response data structures. This allows front end and backend concerns to be separate which allows a lot more flexibility over time for both front end and backend developers. From my limited knowledge of GraphQL, this is still possible but more work than just exposing your db schema types/DTOs.
How many features do teams tend to build that use exclusively existing data, versus new data? How much existing data is lying around that isn't already exposed via API?
I'm not sure that the query layer solves team collaboration and prioritization problems.
Redesigns, UX changes etc, will all change how a UI interacts with data but won't necessarily require any changes to the underlying data model.
Adding brand new capabilities to a system (or refactoring existing ones) will usually requires changes to the GraphQL layer, but this is only a subset of frontend work. Iterating on what already exists also represents a lot of development time.
This seems to throw up the issue of a higher degree of the DB structure getting exposed to the frontend. Faster iteration of the front-end (presumably during a period of more rapid change) comes at the cost of forcing the backend to remain more static.
That seems like a fair trade-off to the oft-seen alternative of the front-end remaining more static because of slow iteration of the back-end, in the sense that I think that there are many situations in which that would be the least bad option.
In my experience GraphQL slows down all teams. If you're on a new project and that's the stack you pick it can work well for a while but as soon as your product is large enough you get multiple GraphQL api's built by different teams that don't behave in a similar fashion. If you're in an org with historical code now you've got APIs that are RESTful and then some which are GraphQL based. Making those work together is either a hack on the frontend or a rewrite project.
Ultimately the thing that speeds up teams, again in my experience, is predictability not flexibility. If you tell someone they have a RESTful API they know exactly how to work with it, document it, etc. GraphQL which is shiny, new, and used by in-vogue orgs is fine, you can use it to get the job done, but I don't believe that it warrants much praise.
You do realize other patterns exist where the frontend team is largely in control of the first endpoint, right? Backend-for-Frontend is one such pattern, although I'm sure that is nothing new either.
> because they don't need to ask the API team to change an endpoint
Bollocks. What happens is you need some field implemented in the microservice or DB that your GraphQL layer talks to. This task gets tossed into your ticket system, gets managed by half a dozen managers, and weeks to months later you finally get the field you need and can finally bubble it up through your fancy toy API.
> GraphQL creates a data graph
does anyone even know what a graph is today? Serious question.
One good fit we may have found is for back office/admin.
In a company you often have APIs geared for client apps, and then internal APIs between services. But rarely anyone develops good APIs for backoffice. And then you have an admin interface struggling to retrieve the data it needs from a dozen different API calls.
Slap a simple GraphQL server in front of these dozen calls, and you have a more streamlined development for internal tools.
Sounds like you agree with the OP; " But rarely anyone develops good APIs for backoffice" describes an organizational problem, and the way you've described using GQL does indeed sound like it's bandaiding that problem.
Indeed, this is more of an organisational problem and the question of what to prioritise next. Backoffice is usually de-prioritised in favor of customer-facing features.
It's a good instinct to be suspicious of new technology. But I have personally seen, many times, what REST APIs can grow into - unless you are very, very careful, "get user/1" can turn into god objects with every field under the sun, non-optional. I've seen `users/l` be over a megabyte with (eg) comments, friends, comments of friends, likes, likes of friends, and every other thing the front end team ever asked for. GraphQL solves that.
Yes, it can be avoided with strict, diligent design. But it often isn't. GraphQL solves the whole class of problem. And that's why I like it, despite my mistrust of "new hotness" technology.
How does it encourage this, and how does graphQL discourage this?
I've always held a strict rule where The R in REST stands for Resource (which isn't true). There's a user, an Invitation (and not an invite action on user, nor a state:invited or invited_at on user). there's a Session. There's links that clients follow, and everything is as small as possible. I really don't see how REST encourages God objects.
I think the point the parent reply is trying to make is not that you cannot follow good practices with REST and that you somehow magically get it with GraphQL. I think their point is that GraphQL makes it much easier for devs to follow good practices and with less resistance.
You can do a lot of the things that Graphql does bu just a regular old JSON HTTP API. It's just not automatic and you will have to choose your own conventions
> I have seen many people try to solve the "too many requests" problem by slowing expanding rest responses into "god" objects.
Fair point.
But I ask my question again, differently worded: how does Graphql solve this? Why does GraphQL solve "many requests" and why can't you solve or avoid this in REST.
My REST endpoints allow a `fields` parameter that specifies the requested fields of the endpoint. Even if you do have a huge object, you can pare it down. To get only `id` and `first_name` on a `User` endpoint, you do `.../rest/User/fields={"id"=true,"first_name"=true}` . Non-standard, but effective. The backend doesn't retrieve or send the un-needed fields.
And you can extend this pattern it by allowing "includes" which would signal to the backend to load and deliver the relations listed in the includes part of the query.
This alone makes it impossible to get backend to return god entities with dozens of relations without explicitly specifying them.
My system has its limitations however. It can't do relational constraints like GraphQL or renaming of fields, but it is likely the 20% that gets you 80% of the way.
To be honest, once you can traverse relationships like this, you've basically just got GraphQL in disguise and might as well be using it. You're going to have all the same difficulties as GraphQL in making it perform well, but don't have the elegant (IMO) query language -- and lose some of the expressivity of fields/relations being able to accept arguments.
Except I dont have to start with GraphQL. I can add the complexity when I need it instead of starting with complexity. Yes I finally got _one_ of the features of GraphQL, but I didn't have to swallow graphql or require everyone else to. They don't have to use the field specifier and it still looks very simple. In contrast to GraphQL.
We have a `user` GraphQL type. It has 200+ fields and resolvers into other data. Fortunately, clients don't need to pull everything.
Well, within one of our frontend apps, someone wrote a "GetUser" query fragment, wrapped it in a react hook to make it easy to use, and now anytime anyone anywhere wants to get a user, even with one field, they're getting 100+ fields they don't want. Anytime someone needs a new field on a user, they don't create a new query; they just add the field to that "GetUser" query.
Now, I've told several GraphQL advocates that setup (in our local community and online), and unfailingly they balk at it. Well, you're doing GraphQL wrong, everyone makes mistakes, you should be more selective, etc etc etc. I think that's fair; being more specific sounds like a good pattern.
Except, we are not certain the performance wouldn't suffer should we move everything to more selective queries. The issue is caching. If you have ten queries each requesting one field, the cache can't saturate until after ten network requests. But, one mega query, and now the remaining nine queries can just pull from the cache. Sure, the mega query takes longer than one mini-query, but its not longer than ten mini-queries.
I only outline this to say: GraphQL is not a magic bullet. Every single thing you can do which would ruin a REST API is also possible in GraphQL. REST API responses naturally evolve into god objects. GraphQL APIs solve the god object issue server-side by saying "god objects are fine", then push the responsibility of not abusing it onto the client (and it should be obvious, the client is the worst place to solve almost every problem, but that's another topic).
GraphQL is easier and better for some things, far harder for other things. At the end of the day, its no worse than REST. I don't recommend it, but that's only just because its new; unless a new technology offers some very easy to express, tactile benefits for your business, just wait for it to mature. When you get down to it, GraphQL's benefits are definitely not tactile, but they're still there, and I think over time it will evolve into something very interesting.
I agree with your point about caching, except, i think, it is missing one important detail that makes your argument less one-sided against GraphQL.
What you described is absolutely correct, except it is only the case if we cache by query. If we cache by objects and fields, none of those issues you described become relevant, and caching by object/field (as opposed to caching by query) in general seems like a better practice imo, aside from certain very specific scenarios.
In fact, it seems like the official GraphQL docs recommend that approach as well [0].
No, its still an issue. If you have QueryA which requests User { firstName } and QueryB which requests User { lastName }, those queries both have to request their data in order for both fields to be cached.
If, instead, you have QueryC which does User { firstName, lastName }, but two usages of it (QueryC1/QueryC2), after QueryC1 requests, QueryC2 can use the cached results. This works whether you're doing Query/Operation level caching or Field/ID level caching. The former example works in neither. And QueryC is trivially faster than QueryA+QueryB because of network overhead.
This isn't necessarily an issue with GraphQL (and, I thought I was clear about this, but: I'm not against GraphQL). Its a behavior of both typical REST implementations and GraphQL. And, to be clear, GraphQL's out-of-box caching story is more powerful than any REST implementation I've seen short of hyper-engineered FAANG companies, because it enables really powerful field/ID level caching across multiple queries. But it doesn't work in this case.
The point is that its still very immature. Even the thought leaders (Apollo being the biggest one and worst offender) write these blog posts filled with Best Practices and Recommendations that often convey horrible advice and flat-out misrepresent GraphQL's actual advantages compared to REST. GraphQL solves a lot of REST's problems; it does NOT solve REST's "god-object" class of problems, like the grandparent comment suggests; and it introduces many new classes of problems that remain unsolved in the ecosystem because of how immature it is (one great example is OSI L7 inspection in many tertiary tools a typical SaaS app has. Many products like Datadog, CloudFront, AWS ALB, etc are capable of doing some really cool and powerful stuff out-of-the-box just by inspecting standard HTTP headers. REST is basically just standard HTTP; your resource is in the path, query parameters, http headers, its very standard. GraphQL is not, so many of these tools don't work out-of-box with GraphQL. People are catching up, but again, its immature).
Thanks for clarifying, I genuinely appreciate comments like this one that go into actual details, without vague fluff or generalized claims. At this point, I am fully with you on this one.
I wonder if this can be statically analyzed? If I have two child components that request bits of data, in theory those requests could flow up the component tree and only be triggered at the root by a component that intelligently coalesces requests: add in some logic to bucket requests by some amount (50ms/100ms) or some logic to explicitly trigger pending requests and it might allow the best of both worlds?
I think any timebox-based batching strategy would effectively just trade frontend performance for backend performance. Your backend would have to deal with fewer requests, and there's always a number of "things" the backend needs to do with every request regardless of the content (e.g. check a token against a database), so fewer requests is nice. But, some components would have to wait up-to X milliseconds to get their data, and if we're talking about a network request that takes 100ms, balancing the value of X to be big enough to actually have an impact, while being small enough to not double the time it takes for some components to get data, would prove very difficult.
The backend performance you could gain is kinda spurious anyway. We're talking about N requests being coalesced into 1 mega-request; I would rather clients send me N small requests, not 1 mega-request. Horizontal scaling is easy to set up and quick to do in real-time; vertical scaling is harder.
And I think, while a solution like this is interesting in the domain of "you've got two sibling components rendered at the same time who's queries could be combined", that's not exactly the issue I described a few comments up. Caching really doesn't enter into play here; it would not be measurably faster to just issue one mega-request for one component and let the other wait for the cache (which is, in the end, what we're talking about). I mean, it saves one network request, but 90% of a network request is just waiting on IO, and if there's one thing Javascript is really good at, its sitting around and waiting. It can wait for dozens of things at a time.
The issue is more specifically surrounding two components being rendered at different times. Imagine a User Preview card which displays a user's first name; the user clicks on that card, which takes them to a new page, the User Profile, which displays both their first and last name. Short of using a God Query for the Preview which covers a broad set of common user fields, like firing a shotgun and hoping you've got the cache saturated for unknown upcoming components, this situation will take two requests. The shotgun approach is what we do, and what many companies do; it works, but its imprecise. It can hurt the performance of the leading components which pulled the short stick, if that God Query gets too big, and as an application evolves you're gonna forget to keep that God Query updated with new things you may need.
This problem is enticing because it feels like there should be a solution, and we just haven't, as a community, found it. I think GraphQL, at its core, has the capability to solve this; its not like REST which is so undefined and hazy that any solution to something super-complex like this would only work in the domain of one company's "way of doing things". I hope one day we can figure it out, because I suspect that a general, easy to use way of preemptively saturating a cache like this would be a MASSIVE performance boost to every GraphQL client that's ever been written.
Meh, people have been selling "technology-X" using this exact same argument since the beginning of time. You could swap out the "GraphQL" in your final sentence for "micro-services" and it'd swear that I've seen it in another thread ^_^
The existence of a God Response / God Object / or just a generally horrific and coupled system strikes me as a particularly human induced problem which no specific technology can actually fix.
I disagree. Where I work (and for some reason I expect this is the case in plenty of other places), APIs don't grow into being shit because the programmer doesn't know that "returning comments on the response of GET user/1" is bad, but because their manager asks them to implement that feature as fast as possible. Given that requirement, of course the guys will just throw the comments in that already existing endpoint instead of building "GET comments?user=John", right?
I'm a big fan of the saying "complexity has to live somewhere" and I think that's exactly what GraphQL is doing: moving the complexity to another layer.
Some people do need to solve the same problems as FAANG, and GQL is a excellent solution to those problems.
Some people also want an agile api surface so they can iterate quickly, GQL is an excellent solution to that problem.
It is also an excellent solution for:
- client side caching
- unified RBAC
- service stitching / microservice hell
- api documentation via graphiql
- decoupling FE dev from api dev
- api automation
- typed api surface
The list goes on.
To say that GQL is a just a band aid for bad leadership is nonsense, and discounts the very real reasons that many many experienced teams are switching to it.
I would encourage you to re-evaluate your position as if you voiced those opinions in an interview with basically anyone I know you would quickly get passed up in favor someone that actually knows what they are talking about.
> I would encourage you to re-evaluate your position as if you voiced those opinions in an interview with basically anyone I know you would quickly get passed up in favor someone that actually knows what they are talking about.
Ha. Now we’re introducing threats. Don’t agree with my technical opinions? You’ll never work in this town again! Funny, funny stuff.
Unfortunately he's somewhat right. Not because the interviewers necessarily know wtf they're talking - they probably don't. But going against the current hype in an interview can only hurt your chances. Liking something like GraphQL, or React, or Framework Of The Month can't really hurt you even if your interviewer doesn't like it. But not liking it can be a real issue! I would suggest at least staying neutral on the current hype stacks in an interview. It's like debating religion - don't go there...
You would expect to be able to have a discussion of the pros and cons, and recognition at the least that other approaches are viable.
> React is a hype stack now?
Yeah, kinda. You definitely need some sort of front end framework, but I feel like there should be something better than react. I use react every day and it’s fine, but I’m waiting for something else to come and take it’s dominant position.
Idk, a lot of the back office apps I build are basically glorified forms with some content pages / dashboard. You really don't always need a framework.
I build apps for living and hiring a svelte dev is not going to happen. Stick to react and go hiking on the weekends with the guys in your svelte meetup.
We're a GraphQL town, buddy. You take your [use of literally any technology which isn't GraphQL, because GraphQL is the best, because nothing else needs to be used anymore] and gtfo of here.
It wasn't a threat, just a suggestion that denigrating some extremely useful tech that is saving organizations tons of time and money may not be a winning career strategy.
> I would encourage you to re-evaluate your position as if you voiced those opinions in an interview with basically anyone I know you would quickly get passed up in favor someone that actually knows what they are talking about.
I would encourage you to re-evaluate how you react to opinions that diverge from your own, especially in an interviewing context. GQL is not a panacea, and candidates should not be discounted because they understand this.
Boo. Let's not be too close minded. I'm a FANNG guy. A lot of our problems aren't even these mystical "FANNG problems" people talk about and get solved by REMARKABLY boring tech. So, I'd welcome his opinion in an interview. ^_^
Picking a non-sexy, non-scalable, "wrong" technology that does nothing more than solve the actual requirements at hand is a rare and amazing quality for engineer to have imo.
Everyone wants to build infinitely flexible, infinitely scalable machines using the most rapid iteration tools possible as though that's what "engineering" is. But sometimes... all you need is a REST API. Sometimes you need GraphQL. Sometimes, all you need is to stuff data in a bucket somewhere and call that an "integration point". All solutions have trade offs. Pretending otherwise, or faulting others for weighing those trade offs differently than you, is silly.
And then 50 people stuff data into different "buckets" and call them "integration points" and you spend months refactoring their horrible choices after you have identified why your services can't scale.
Non sexy "wrong" tech is exactly that. Pick smart tools that do the work for you so that you don't have to babysit your teams choices and micromanage every project.
I have weighed the trade offs, and it is literally my job to identify the problems that come from them.
Ah, ok, guy. We get it. It's either your way and your preferred tech or it's total unbridled chaos which is doomed to fail. Turns out there IS a silver bullet after all. I'm embarrassed.
Yes, because I am the only person on the planet advocating for gql, and more broadly advocating against allowing individual developers to drop data into "buckets" or whatever point you were trying to make about how freelancing in production systems should work.
That is exactly the kind of problem solver I like to work with. Most of the time, “boring” tech will solve the problem cheaper, faster and as reliable and scalable as any shiny new tech.
I work with GraphQL, REST APIs and even JSON RPC APIs on a daily basis and when you truly use those tools, you get to know where they really shine.
If your workplace is solving FAANG type problems sure you would want someone who supports the concept of GQL.
Is everyone you know solving FAANG problems? If they are not are they emulating those FAANG companies tooling because they expect to be one or work at one in the future? Or is it a type signaling?
There is this over tooling over scaling wave going on.
Most startups fail because in their limited investments they over tool and under sell.
> I would encourage you to re-evaluate your position as if you voiced those opinions in an interview with basically anyone I know you would quickly get passed up in favor someone that actually knows what they are talking about.
If you are a person who is not capable of seeing drawbacks as well, then you would also be a bad engineer who should also be passed up for other candidates, who are more capable of evaluating both the benefits and drawbacks of certain solutions.
GQL has issues like every tech does, but it feels so much more ergonomic from an api consumer point of view.
Simply point Insomnia at the base url and it’ll introspect the schema and provide typed query auto completion. No dozens of requests to different endpoints with different query parameters than can only be kept track of by having the api docs open on a second screen.
It's only ergonomic if you've never done REST before.
I'm not being flippant. If you're already using REST tools such as Postman and every caching tool in existence (browser, http proxy, etc. etc.) then GraphQL tossing it all out is the exact opposite of "ergonomic."
The caching story in GraphQL is a joke. What the browser gives you for free with GET caching takes weeks and months of fine-tuning and tweaking and head scratching with something like Apollo. Then you'll probably try decreasing the payload size (there's a third-party solution for this), or batching requests together (guess what... there is a third-party solution for this too). The amount of tooling and implementation work GraphQL needs to get up to par with built-in REST is pretty incredible.
> For me GraphQL is the epitome (in the Web tier) of 'we need to solve the same problems as FAANG does'.
I work at a small startup. We use a REST and Redux architecture. It's worked very well for us, but we're starting to hit some pain points. As we look to re-architect, our list of challenges pretty much mimic the challenges GraphQL looks to address. These aren't scaling issues or "big company issues". In my opinion, they're core issues with every client-server code base.
* Client Data and Statement Management
* API Coordination and Versioning (even more complex if you have a public API)
* Payload Management and Relational Data (it can be very expensive to pro-actively return embedded/dependent data, so you need to manage it somehow)
* Caching and De-deduping
* Typing and Data Interfaces between Client/Server
* Error Management (not that hard to standardize, but still something you need to account for)
There are issues that you get with GraphQL that are generally much easier to solve with REST, though. While it's easy to set up a GraphQL API that technically makes your whole graph available, going off of your default resolver functions alone is going to cause serious performance issues as soon as queries start to get more complex. The default behavior is basically n+1. To fix that, you have to do query introspection, which is significantly more complicated than just having a dedicated endpoint. Depending on your data sources & how easy it is to cache, this can be more or less of a problem.
This isn't to say that GraphQL is bad or anything, but there are definitely some gotchas that are important to evaluate before diving in.
The n+1 problem can be fixed without introspection by using dataloaders: https://github.com/graphql/dataloader. It's actually quite pleasant to work with them, but it's definitely one more thing you need to know.
This means you can afford a lot of technical debt, even such technical debt as might be incurred by GraphQL (as argued by the post and many people in this conversation).
The concerns you've posted are certainly valid, but GraphQL is not the only (or even necessarily best) way to address them.
If you have a huge engineering staff like FB, then perhaps it's better to just "move the complexity to server side", but for most businesses that not what's going to happen. What's going to happen in practice is DoS galore.
I agree that GraphQL is not the only way to solve them, but it does provide consistent approach to address most of those. At a startup, it's very, very beneficial to be able to point to externally maintained documentation and best practices. It's one less thing to do internally and can help to onboarding new employees more quickly.
I'd rather take on technical debt related to our product features than to load us up on fundamental networking and caching issues.
That's fair. Reasonable people can disagree about these things.
EDIT: Sorry, a bit of a rambly post, too tired and emotional to rephrase.
I will say, though, that "fundamental networking and caching issues" sounds very... weasel-wordy, if you see what I mean? It's not very concrete about what the actual problems you might experience would be. (Yes, latency and huge numbers of requests are issues, but is it really an issue until you get big enough?)
Almost all successful applications in existence until about 2018 (or so? Not sure exactly when GraphQL was invented) has done just about fine. If we're talking about a brand new type of application which couldn't have been done without it, then fine. If not... well, we're not talking about technical limitations.
I truly do see the appeal of GraphQL for developers, and especially the fast decoupled iteration that it enables, at least theoretically. The thing is that when you need more data on the client, you still have to add that data on the server... somewhere. It's great that the client can choose the overall "shape" of the data, but that doesn't solve the problem of the data not actually being on the server.
> You'll likely never be in a situation where over-querying via a non-granular REST call will ever be an issue worth optimising around.
Sure, but that's only one advantage of GraphQl. Personally, I'd use GraphQl even for the smallest of apps. With statically generated sites, you can forgo a back-end server and just setup a GraphQl instance. It's a one-time cost to learn, and then you easily setup your APIs and if you are using React/Vuejs, it's even easier to integrate with your API.
Well said. Plus, the fact that proper query-based load balancing now has to read, parse and interpret (based on the currently deployed application) the entire HTTP request in order to make any balancing decisions, whereas header-based (see: path-based) balancing only had to read a small portion of the request before forwarding all remaining connection traffic to the destination backend service after request replaying.
GraphQL has never made sense to me for anything beyond toy or small-scale projects.
I would strongly disagree. Scale is scale, and though I don't have the volume problems that FAANG have, I also have substantially fewer resources.
Being able to very quickly connect a series of tools and tech together in a way that is selective of the data being moved around saves me money and time, period. That matters.
You posted this comment 10 hours ago and it's at the top, despite the down votes and biased opinions by people who have a lot to lose if you're right. The silent majority seems to agree with you.
Working for a company much smaller than FAANG, I've seen issues with REST. However, the waterfall problem was a small issue compared with problems with bandwidth and server-side compute when you are processing and returning more data than is actually needed. That isn't to say that graphql is a magic bullet for those problems, but the issues with REST can show up far before you get to FAANG scale.
I'm surprised at all the people that prefer REST over GraphQL.
I'm a developer of my own projects for fun. I don't work in tech. My frontends are on iOS / Android / the web with Typescript. So my confusion is from a perspective without expertise.
I started with REST via Django and a few others, and now I've switched to GraphQL. I love GraphQL over REST backends due to the type automation tools such as GraphQL Code Generator and query tools like Apollo. Also being able to construct a query and access children via one request is super nice. For example my old REST APIs call for a post, then get pictures for that post, then get comments for that post, then gets the username and other user data for the owner that made the comment. It's four requests. My GraphQL requests just get them all in one customizable request. Post can contain pictures and comments and all their properties. Comments can contain the owner of the comment and all its properties to include things like username.
The result is a typescript object that is strongly typed and has all the data I need. Before GraphQL, in REST, this would be four requests, three of which are in series (post -> comment -> owner to get username). I know I could make a custom REST API to do the same thing, but it was just so easy in GraphQL, I didn't have to worry about it.
I'm not working in teams, I'm not creating a super large backend, it's not complex projects... so I don't know what I don't know.
But what am I missing? Maybe not everyone needs / uses the typing I do? That's the big benefit for me. Maybe not everyone cares about being able to query children (or create children via a nested create)? Maybe these things were easier than how I was doing it in REST?
These are all excellent points in favor of productivity with GraphQL. I always avoid new technologies for a few years to let the hype cycle mature (for example, everybody talking about how great mongodb is and writing blog posts about how they migrated, followed two years later by everybody talking about how terrible mongodb is and how they had to migrate to posgresql). As a dev working on a commercial software project, especially if you're in leadership, you have to look very carefully at every technology you introduce into your stack, because you are going to be supporting it for years. If it turns out to be the wrong decision, or you get caught out by a bunch of edge cases that weren't well known in the early days, you can end up losing millions of dollars in productivity, and possibly killing the company when you can't fix bugs and ship new features. So I've been suspicious of GraphQL, but keeping an eye on it. I still don't know if the productivity gains you get up front are actually technical debt in disguise, but if that turns out not to be the case, and it really is a matter of only having to write one query instead of making five requests and several dozen lines of types, validators, and async redux middleware, I'll be happy to adopt it in the future.
For example, what you described about making 4 requests with your 'REST' API, you didn't have to do that. YOU made that terrible API. That's not a feature of REST, but you seem to have mixed the two up in your head.
Feature where you can write an endpoint to return whatever it is that you need. Granted, it’s not automatic as in some GraphQL frameworks - not sure if that’s what you meant by “arbitrary”. But then again, such things are a step beyond just using GraphQL as a protocol.
REST: Any time there is a new "view"; you need to go to your server and write a new endpoint.
GraphQL: You can stitch data together however you want; as long as that data is defined.
So for example if I need name of someone and the url of their children; querying it alone is enough with GraphQL whereas with REST either I need to fetch multiple times or write a new endpoint that serves both together.
The idea of a REST endpoint is to represent a resource, not a view. How will you bring good RESTful API design together with the requirement of wanting an API that serves one very specific view that depends on multiple REST APIs. This seems to be in conflict doesn't it? What's your idea on resolving this conflict without abandoning the principles of RESTful API design?
> Maybe these things were easier than how I was doing it in REST?
That might be the case. Those things (such as returning children - and generally crafting a custom endpoint for specific use-case) are indeed very easy in my language/framework of choice (ASP.NET with a little help from LINQ).
I also get automatic generation of client-side data classes and strongly typed functions that encapsulate endpoints on the server using a small code generation framework that literally took 2-3 days to write (it's really not that complex).
> If you're shipping multi-megs of JS to a client don't then pretend that micro-optimisating the API call waterfall is your KPI, it's just disingenuous at best.
It absolutely is the bottleneck in almost every web app that relies on Ajax fetches. The latency is an absolute killer.
On every app that I've optimised, I have to get people to stop going with their gut and look at the traces (both synthetic and real-user). People generally think they should be optimising their JS execution. But in fact the most important thing is usually sequencing loading correctly, followed by minimising JS bundle sizes.
Modern browsers are getting really good at parallelising loading and parsing JS and other resources. But if you're whacking some fetch in there that happens as a result of JS execution then you're generally looking at a wasted 300-500ms for most endpoints/device combos.
Disagree - GraphQL is a legit better way to build APIs.
As a backend engineer, I publish a schema of all the available data - the frontend can fetch it in any shape it prefers. Web UIs and mobile UIs often have different views, so they want different data, and fetching it in one request or many is up to the preference of the UI.
I don't have to build different REST endpoints presenting some data in a different shape for performance reasons or because different applications wanted to request the data in a different way.
As a frontend engineer, all the data is often already there unless I'm building some new feature the backend doesn't understand yet. I'm free to refactor my application without bothering changing the REST API - and GraphIQL lets me inspect the api and mock queries for how I might fetch the data for a given view.
It's a cleaner contract to let different people get their job done with less fuss - game changer.
I respectfully disagree, at least in some contexts. If you support an API that has multiple clients with ever-changing needs, GraphQL can make your life much simpler, with much less code. I can only speak to the experience of using Lacinia in Clojure, but I found it to be fairly easy to use.
Core Contributor of urql here, another JS GraphQL client.
I think this post is very good at stating why the particular post it’s referencing (“Why GraphQL” in the Apollo docs) isn’t a full picture overview, and it succeeds at that very well, but I think it doesn’t go on to expand on these views just as much as I’d like to.
If we look at popular comments by the GraphQL community on this it isn’t hard to find that “the quickest & easiest client is to just fetch a GraphQL API” (similarly said quite frequently) and that’s an excellent point.
But going on to say:
> However, you should always consider the cost of adding a GraphQL client to your frontend.
This is definitely true, but as a creator of another GraphQL client I’d say that there are major benefits as well, the main selling point of Apollo, Relay and urql (for the latter this is optional) being that you can utilise a normalized cache.
But these tools often provide great frameworks to solve some of the problems that are stated to be woes with GraphQL, like persisted queries, subscriptions, file uploads, etc. So they’re a great starting point to dip into multiple parts of the community and get out-of-the-box solutions for your problems.
And generally I’d say that sums up GraphQL: it’s not novel or anything new. Instead it combines a lot of ideas into a solid community and ecosystem. With tools like Swagger or gRPC it’s easy to see how any part we look at for GraphQL isn’t novel.
What is great is that the exact set of problems it solves it does so with a larger (and growing) community and a standard that encompasses multiple of these solutions.
Finally, I’d say again, GraphQL clients and servers aren’t “all of GraphQL,” Apollo isn’t GraphQL (although they’ve made themselves synonymous with it) and hence there are different tools, clients, and libraries to create GraphQL servers, clients, and interact with GraphQL APIs. As a user you’ll still have to choose, but a lot of the good parts come from agreeing on one language and standard that allows for introspection and the ease using which we interact with these APIs on the client-side, from simple HTTP calls to more complex caching clients.
Hey, thanks for your reply. I think you guys have done an amazing job creating a very powerful GraphQL client. However, to me "smart" GraphQL clients don't make much sense. My approach with WunderGraph is the following: You write down all your Operations using GraphiQL. We automatically persist them on the server (WunderNode) and generate a "dumb" typesafe client. This client feels like GraphQL and behaves like GraphQL but is not using GraphQL at all. It's just RPC. This makes using GraphQL more performant and secure at the same time. Additionally it's a lot less code and a smaller client because those RPC's are a lot simpler.
That sounds interesting! But isn’t this like persisted queries (the Relay kind and not Automatic kind) without the benefit of prototyping your queries as a front end dev as you’re working on the front end?
I’d say that’s completely fair still, just wondering. I’d also say I understand the carefulness and stance on “smart clients,” i.e. normalized caching, which is why this isn’t a default in urql, but without it I think the discussion here is much more nuanced.
It’s so to speak much easier to rely on an argument with a smarter client and the Apollo ecosystem, than the rest. Anyway, I like your approach with Wundergraph so I’ll definitely check it out!
I was asking myself an important question. When you write a Query, what activity are you actually currently involved in? You try to understand the API and want to query it. What's the easiest way to understand an API? Read the documentation? Where is the documentation? It's the schema, hence GraphiQL/Playground. So why would you want to switch back and forth between Documentation and Code when you want to understand an API? On the other hand, if you already use GraphiQL in your workflow, how does this look like? You write a Query in GraphiQL, then copy paste it into your code. Now if you want to add something else you go back to GraphiQL, search for another field and copy paste again. Compare that to WunderGraph: You keep getting back to GrapiQL and extend your Queries. You hit save and the code-generator re-generates the client. You don't even have to change the code if you just extended a query. The function call in the frontend simply returns more data. I wrote a feature page about this: https://wundergraph.com/features/generated_clients I'd really appreciate your feedback on it!
It all seems very interesting, I may try and experiment putting it in front of my current prod GraphQL schema and making a few queries, once I get the auth stuff figured out. One question though, is any of this going to be open source? The on-prem-first focus you have is certainly a selling point for me as I already run my entire backend in Amazon's ECS so adding another service for the wundergraph would be very simple - however, I'm always weary of using non-open source software that I can't fork and patch, as I've had to do that many a time due to not being able to wait for patches to be upstreamed.
Regardless, I think the points you make in your blog posts are spot on, and I'm looking forward to watching this project evolve.
We'll open source all of it except the control plane and a component we're currently working on which lets you share, stitch and combine APIs of any type across teams and organizations. All the other parts will be open source, the engine, the WunderNode, CodeGen. We don't want to be locked into a vendor ourselves. You can always not use our proprietary services. The core functionality described above will always work offline without using any of our cloud services. We will offer a dirt cheap cloud service where we run WunderNodes on the edge for you but if, for any reason, you don't want to use this you're free to host your own Nodes. I'd love if you could contact me and we have a chat about your use case. I'd really like to get your take and build out the next steps as close to user expectations as it can get. I don't want to build something that doesn't work for the community.
What I can't quite glean from the docs is how you can do row-based security, ie authZ on user ownership of a row when you're trying to filter by certain things other than the ID.
Another thing is mutations - does WunderGraph support mutations at all yet? Security for those is also even more important, as you might want to restrict what entities you can attach to the entity you're creating etc.
I guess the root of my question is how much business logic can you achieve with WunderGraph itself? It's probably not something that's necessary if I really think about it, if it just handles the authN and then passes tokens with claims nad user IDs to the data sources, Hasura/Postgraphile et al can handle the row-specific authZ and business logic, and then WunderGraph can just be the BFF for each app client. I'd still definitely use it in that setup, as the generated clients and federation subscriptions would be a marked improvement over Apollo for me.
WunderGraph can inject variables or claims into a query. If you want to implement ownership based authorization e.g. with Hasura, Postgraphile, fauna or Dgraph, etc. the value to determine ownership needs to be part of the schema. E.g. a owner field on a type or a permission table/type. Then you supply a owner ID from the claim and that's it. This works because you don't allow this value to be submitted by the client. It always gets injected from a claim in the JWT. This leads to a big advantage over using one of the Auth implementations from said vendors like e.g. Row level security. You decouple Auth from the storage. You can always move to another database and are not stuck with a specific Auth implementation. You could also delegate Auth to a completely different service like open policy agent. If you don't want to use WunderGraph anymore you can re-implement the logic in a Backend for frontend. This way you evade vendor lock in for both database and middleware layer.
Mutations are fully supported. When generating clients all we do is treat mutations like POST requests and queries and subscriptions like GET http2 streams falling back to http1 chunked encoding.
WunderGraph doesn't want to contain business logic. We are the front door, making everything secure and establishing a stable contract between client and server. We mediate between protocols and we map responses so that every party gets data in the format and shape they expect. Other than that, if you want to add custom logic just run a lambda with any of the supported protocols, e.g. GraphQL, REST and in the future gRPC, SOAP, Kafka, RabbitMQ, etc. and we do the mediation. But as were the middleware layer I'd try to not put business logic into this.
That said I'd love to get in touch and discuss how WG can add value for you.
That does sound very interesting. I believe the issue lies in the fact that this is a workflow-based “sales pitch.” What I mean is that this is a difference that doesn’t always apply depending on what tools you use (like client dev tools, type generation / hints, etc)
But what it does do is constrain. Now, constraints are great. They’re always a great tool to introduce new innovations. What I’m ultimately thinking is, how much do you bring to the table compared to persisted queries and tools like GraphQL Code Generator and the added flexibility that comes with those tools?
First, with this approach you're able to add authentication rules into operations, not just the schema. That is, you can inject claims from the Auth jwt into variables. This gives you a lot more flexibility than schema directives or a resolver middleware. This feature is unique to WunderGraph.
Next we're able to execute the persisted query on the edge using etags for low latency.
WunderGraph adds the capability to use @stream & @defer on top of any existing GraphQL or REST API. You don't have to change anything on your existing GraphQL server. This works especially great with Apollo federation. WunderGraph is a replacement for Apollo gateway. We support federation with subscriptions, @defer and @stream, another unique feature to WunderGraph. The generated code gives you simple to use hooks, in case of react, to fetch data or streams.
Finally the generated code is authentication aware. WunderGraph has its own OIDC server. Generated clients know if authentication is required for a specific persisted query. This way a query will wait until the user authenticates and then fire off.
I think this should be enough. I don't want to get too much into the details as there are a lot more benefits.
But I don't think it addresses why I'd want a "smart" GraphQL client: normalized caching on the client.
Say I have a dashboard where multiple panels on a given page make their own requests, since the panels are shared between many pages. But they share some objects. If I get updated data in a request from one panel, I'd like to see that update in all panels, without triggering more requests.
Side note that a magic layer to have each of those components combine their requests into one would actually hurt performance, since it's better to load the requests in parallel. And manually merging them into one would be quite a chore.
Client side caching with a normalized cache implementation is very hard to get right. I see why you would want that feature and if it were simple to implement I'd always want to use it. However I think we can get away with a solution that is a lot simpler than normalized caching. With persisted Queries we can apply the "stale while revalidate" pattern. This means we can invalidate each individual page and would have to re-fetch each page in case something updated. This is some overhead but the user experience is still very good. Normalized caching in the client can get super hairy with nested data. In addition, normalized caching adds a lot of business logic to the client which makes it hard to understand the actual source of truth. From a mental model it's a lot simpler if the server dictates the state and the client doesn't override it. If you allow the client to have a normalized cache the source of truth is shared between client and server. This might lead to bugs and generally makes the code more complicated than it needs to be. Is it really that bad to re-fetch a table? I guess most of the time it's not. I've written a blog post on the topic if you want to expand on it further: https://wundergraph.com/blog/2020/09/11/the-case-against-nor...
> Client side caching with a normalized cache implementation is very hard to get right
Absolutely true! When I worked on this at $prevCo, it was tricky and sometimes caused bugs, unexpected behavior, and confused colleagues.
I will say that a proper implementation of a normalized cache on the client must have an ~inherent (thus generated) understanding of the object graph. It also must provide simple control of "whether to cache" at each request. Most of the problems we experienced were a result of the first constraint not being fully satisfied.
My impression is that Apollo does a good job on both of these but I haven't used it so I can't say.
I'll also note that the approach of "when one component makes an update, tell all other components on the page to refetch" sounds like a recipe for problems too – excess server/db load, unrelated data changing in front of users' eyes (and weird hacks to prevent this), etc.
Of course, with the wundergraph architecture, it sounds like answer to these questions would simply be to load a given table only once per page – which means no more defining queries on the "panel" components in the dashboard, for example.
All tricky tradeoffs! The right answer depends on what you're building. The Wundergraph approach sounds pretty cool for a lot of cases!
For many use cases, adding an avoidable server round-trip between a user interaction and a view update is an absolute non-starter. Milliseconds matter.
Does it lead to greater complexity somewhere, and all the issues around making that complexity bulletproof? Sure. But the user experience is so viscerally different that some will demand it. I think it’s admirable to work on getting that complexity correct and properly abstracted so that it can be re-used easily.
You can avoid this problem by using Etags, stale while revalidate pattern as well as prefetching. This keeps the architecture simple without any major drawbacks.
Aside: why is there not an RSS feed for the WunderGraph blog?
I think Jens Neuse is making two important observations about GraphQL:
1. GraphQL's single URL/endpoint [1] is possibly an anti-pattern
2. ETags are important for Cache-Control and Concurrency-Control on REST endpoints
The concept of prepared statements is useful for my SQL-centric brain. WunderGraph effectively creates a REST endpoint for each prepared statement (GraphQL DML). Like prepared statements in SQL, WunderGraph uses query metadata to determine the types of input parameters and the shape of the JSON response.
Kyle Schrade makes an important point about canonical GraphQL queries: response payloads can be reduced by filtering JSON fields, similar to SQL projection (i.e. the columns specified in the SELECT clause). It seems that WunderGraph can potentially support both approaches by allowing optional GraphQL queries on each REST endpoint that can be used to filter the endpoint specific JSON response.
I don't see a problem allowing a generic GraphQL handler. It's just that I don't like the approach of allowing arbitrary queries from clients you cannot control. If this use case has a lot of demand I don't think I wouldn't support it. I'd just rather implement a seamless developer experience for code generation so you don't really want to not use it and lose the benefits.
I think we are on the same page. From my perspective, arbitrary queries are a vector for a Denial of Service event (both intentional and accidental). This has long been one of the use cases for Stored Procedures in SQL; restrict the public interface to guard against expensive queries (large scans and sorts). Faceted Search [1] may be a counter-example but I suspect that these interfaces are implemented at least partially with Full Text Search indexes rather than purely dynamic GraphQL/SQL.
It might be a useful exercise to prototype an online shopping site using WunderGraph.
I didn't know WunderGraph, but this sounds similar to OneGraph [1], i.e. you write your GraphQL query, identify its input if needed, then persist (once) the query on the server. This returns a unique query ID that can be used to execute that query server side. In OneGraph, you can use just HTTP for that, no need for a GraphQL client library. You can use any HTTP client to trigger a POST request with the persisted query ID and its input params in the request body. This way it seems a bit easier and simpler that your approach with RPC in WunderGraph. I need to read your docs to have a full picture though. ;)
Compare to REST, GraphQL have many advantages. However, IMO the tooling is still not there yet (Especially the caching, batching/data loaders are PITA).
One of the biggest selling point rarely come up is that you get the API docs for free through the playground. No more Swagger bad API
You might get reference documentation for free but you don't get real, proper documentation that actually teaches the user anything. So basically the biggest selling point (for you) for GraphQL is the same as biggest selling point for Swagger? The quality of those reference docs is more based on the developer writing them, rather than the technology who allows it.
I'm only contrasting it to reference documentation. So in the case of GraphQL, you get reference documentation that shows you exactly how it can be used. But it won't show you _why_ you'll use it, or _what_ it can be used for. It also doesn't show what invariants you're working with, or in what way the endpoints are otherwise restricted with.
Real proper documentation is not just a list of endpoints and their attributes but explanations of those as well as other things.
The original comment said "One of the biggest selling point rarely come up is that you get the API docs for free" while comparing it to Swagger. Both GraphQL and Swagger gives the same ability to generate API reference documentation.
So how is that the "biggest selling point" of GraphQL when it's not even new in the ecosystem?
Because swagger docs are defined via proprietary yaml definitions whereas graphiql exposes a more useful interface that is actually derived from your code, which in most cases is automatically generated from your DB model.
I've written a lot of swagger docs over the years, GQL is a massive improvement.
Being able to predict how your customers use your API has a strong impact on how you deliver the data behind the API.
If we're talking about highly interconnected objects in an API, it would be expensive (from a DB point of view) to arbitrarily add indexes in the long shot case that someone may use a selector on that property.
Equally, when data is highly interconnected, by designing an API that focuses on particular consumption patterns, I'm able to add custom functionality, pre-processing, or highly customised queries/indexes to ensure the data is read as fast as possible.
Poor performing API's are bad for the consumer, bad for the database, and bad for the art of data.
There's a balance between centralization and independence in software models that is so hard to balance right.
MicroServices, GraphQL, and Docker Swarms are examples of technologies that, if done right, can be enabling, and if done wrong, will pull the ship to the bottom of the ocean.
It's not that hard. For sure it's not trivial, but the thing you just said about REST is equally true for GraphQL -- you can literally solve performance in the same way. Ultimately fulfilling the data requirements for a use case boils down to composing the results of a bunch of I/O calls, the only real difference between REST and GraphQL is how these calls are triggered and their results composed.
Sure, but the design of GraphQL, and the majority of the GraphQL backend tooling, lends itself to performance issues much more strongly than a boring REST API. I don't know if there are alternative backend tools, but my experience has been quite painful.
The "graph" part - GraphQL seems to want you to build these big interconnected webs of types. But there isn't good tooling on the backend to deal with resolving relationships between types efficiently. Someone decides they need user.friends.pets.names, and now my backend code is doing 3 DB round trips because my GraphQL server lib doesn't understand it can turn the relationship between the types into a JOIN. I decide that's no good and the query needs to be faster, the alternative is I have to do the JOIN every time even if the client didn't actually request friends. And if I'm going to overfetch from the DB, might as well send that data to the client anyway?
My experience was that because of how backend GraphQL servers are written, it becomes very challenging to reason about performance. It's hard to think about how your nice type resolvers are going to interact, and fan out into some nightmare n+1 query problem performance pit.
I know there are some better tools than this, which I sadly haven't tried...
But if you were fetching the same data with a REST API (one that doesn't allow inclusion of relation fields, such as the JSON-API spec), you'd be doing the same amount of I/O and have the same horrible n+1 problem just between the client and server rather than inside the server, so it's spread across numerous requests rather than just one.
Tools like Dataloader solve the n+1 problem quite effectively, and they've been around for about 5 years, making it a solved problem for the overwhelming majority of GraphQL's open source existence. If you look at the examples I wrote in this article (https://andrewingram.net/posts/optimising-graphql-request-wa...), in the waterfall charts each "call" is roughly equivalent to one simple (and usually easy to optimise) database query. I don't want to unduly trivialise the work in getting Dataloader properly integrated, but I will say it doesn't take a lot to start seeing the fruits of your effort.
I think you are confused about what the parent comment said. The point is that the n+1 problem is usually solved on the database level in case of REST and the endpoint is also changing in tandem to reflect the DB changes. There is no client and server fan-out as you describe.
And the second thing is that solving something by slapping an unknown library into the stack instead of using the DB tools which are readily available out of the box doesn't make much sense IMO.
Sure, I'd have the same n+1 problem. But this time the frontend devs will notice it when they try to use the API. With GraphQL our frontend team doesn't reason about the backend performance characteristics of their queries until they kill perf on prod.
At this point it's sounding more like you don't trust your front-end devs. Fixing that is going to be more critical than any technological choice you make.
Not quite. There is an advantage to being "chatty" that GraphQL proponents don't often mention IMO. You can load balance each of those join requests, cache those GET requests even if they make up only a part of the overall query, shard the storage to multiple servers, rate limit, etc. Spreading requests is usually a good thing; with HTTP/2 the overhead of those extra requests is extremely low as well. It allows sharded processing with approx equal load between nodes at the backend.
Its much easier to define SLA's and manage your traffic profile/platform when the load of each "query" is definitely quantifiable and granular - unlike a GraphQL query.
Then people come to me and say - well you can pre-can your GraphQL queries so that you know which queries are going to be run therefore you have known performance. At which point I say - why not just make a specialised REST endpoint with that query inside it?
I see it as a good backend-for-frontend adapter technology where a bulk query can be sharded into individual smaller ones using core backend services for large use-case specific views. If a query uses too much resources then the GraphQL server and/or a client ID can be rate limited by the backend servers, etc. Which is why I think its mainly a JS thing to date IMO - it doesn't solve many core problems for most backends - it solves typical front-ender dev's issues who can't/don't want to write server side code.
I don't get "not that hard" part. With REST I have a finite set of queries to optimise. With GraphQL I have unlimited set of queries. How I supposed to optimise for what I don't know?
One good example - 'users' and 'comments' tables with natural relationship. 'Comments' grow to unreasonable size and split into different tables, fresh comments stay in 'comments', old comments moved to another database with cheaper storage. With REST it is easy, I get a query like 'get user's A comments from X till Y'. I have to deal with two dates and based on that figure out how to fetch data.
With GraphQL I can get query like this but also something like this 'get user's A comments from user.signup_date.year till user.signup_date.year + 1'. I suppose I would have to deal with query AST to figure out if it queries archive dates or not. This sounds like 100x more complicated compared to REST.
GraphQL doesn't exclude hand-crafted database queries. If that is what needed you can perfectly make that fit with GraphQL. And if for some reason it won't fit in GraphQL, you could still create a one-off REST endpoint.
And also introduce all REST tooling in addition to GraphQL. At this time people often start thinking "why I didn't start with REST in the first place?"
GraphQL is not like REST at all because if something is not defined in GraphQL, it cannot be done. For instance Graphql servers cannot have dynamic fields in models (example aggregate queries)
I created a no-code tool that could do joins, filters, and more with GraphQL, so I really don't see your point. You just need to do it a bit differently (same as REST, and if you follow REST 100%, good luck with n*m calls when you want to join two resources that you don't know from the start):
GET clients [client 1, client 2]
for each client
GET business (id = client.id)
Now think you can join with business, jobs, invoices, employees, etc etc, and tell me how to do this in rest without basically recreating a query language?
I did, the same way you would do with a REST API. you specify a format for a field (in my case, the 'where' and 'join' where JSON structures that you passed as parameters)
Then you write the resolvers that parse that. Pretty much as I would expect you to do it in REST.
(mentioned it in another post, I created a no-code tool that did this, for random data and entities created by the user per tenant/app, so I know the issues with GQL, but I can assure you, doing the same with REST was 10 times harder (api started as REST and moved to GQL after 6 months)
> My personal pet peeve is when the community keeps advertising benefits of GraphQL that are very generic and really have nothing to do with GraphQL.
Douglas Crockford taught me a really valuable lesson here... in Javascript: The Good Parts he had something directed at the haters of Javascript, that stuck with me. But I think it applies here too. GraphQL and REST are tools/patterns that have pros and cons. All tools have pros and cons. Why would you get mad at a hammer for not being good drill? Because that is what people do in our industry and it's silly.
I tried two years ago to write an article with this in mind, and the conclusion I came to in [0] is that it is an abstraction. Nothing more, nothing less. It's up to the individual to determine whether that abstraction makes sense to them.
Haters are always gonna hate, and I do appreciate your taking the time comparing and contrasting the two. Too often articles that say "Hey wait a minute here, we might be drinking the koolaid for x" come across as contrarian and spiteful. I think you managed to keep a respectful tone while asking important questions. Thank you :)
Thank you! When I was less experienced I introduced a lot of technologies to the companies I was working for. I thought I'm doing the right thing. If I were fully honest I just thought these tools are amazing and I wanted to have a play with them. Over the years I learned that I was wrong a lot of the time. I introduced kubernetes to a company that never really had the need for it. It wasn't the right move for them. I didn't fully understand the business. I think, as developers, it's important to develop balanced views and get better at decision making. It's important to not focus on tech too much but understand the business implications and derive the strategy from that.
Junior devs neither understand the business nor the technology, but they get promoted to senior dev anyway after 6 months of bootcamp and 2 years on the job.
May I ask if you didn't have enough experience how/why were you allowed to make such decisions? Is this common in some companies that anyone can make fundamental decisions regardless of number of years in service or experience with the technology?
Sure! The issue is best described as the Peter principle. They guy who hired me didn't know enough to hire the right person. He was beyond his capacity and then it was me. That's the Peter principle. At some point in our career this might happen to allot us. We get promoted into a position we're not capable of.
This is a refreshing read, every time I ask someone what they like about GraphQL or read an article about the benefits of GraphQL I get the same boilerplate, non-answers that made me avoid GraphQL on my latest app after working with it on 2 freelance projects over the last couple years.
The tooling around Apollo is pretty good, and that’s great but so many of the “why GraphQL” arguments are either short sided, assume you are doing REST badly, or imply you are an organization that is much bigger and has scaling problems most of the projects I’ve worked on do not have. So far I am very happy I went back to a REST API.
Oh and here’s another REST benefit: when working on my REST API I spend most of my time thinking about good API design and testing practices. When working with GraphQL I spent most of my time figuring out how GraphQL ecosystem libraries worked. I would much rather spend my time thinking about how to do the job well than how to glue together an ecosystem of tools that someone else designed. Admittedly this is a very subjective line to draw, for instance I loved Rails and some people make the same criticism of Rails that I make here for the GraphQL ecosystem.
GraphQL is great when your entities are complicated and interconnected with each other. If you just need to get one user object, it's not different from rest. If you need to get user, then 5 of his posts, then 50 of comments for each post and then 100 reactions for each post, all connected by IDs in your DB, GraphQL allows you to do all of this in a single HTTP request, single SQL query and with 0 lines written by backend developer.
(This example is pretty silly, but I have very similar and not silly examples that I just can't share because of respect for my employer's NDA).
My experience is that giving front-end developers who does not understand databases the ability to do this is a great way of killing performance across the board.
I don't particularly want that to be easy, because I've too many times had to clean up the consequences.
If you have a team where everyone understands the database implications, then awesome. In that case this consideration may not apply.
It can be a very bad thing or an acceptable payment for developer velocity, based on what's your business priorities with the project.
I have a couple of issues that I worked on that started exactly like this: front-end developer implemented a feature based on GraphQL, but when we deployed this feature, we quickly disabled it after receiving alerts from production database, and re-enabled it back only after backend developer (me) went and worked on database indexing.
But for my team, at the current point of the project's development, this scenario is a net positive overall, because we're exactly in "move fast and break things" mentality, which suits our product and our place in the market. If our project would require a lot of 9s, or worked with very confidential data, or had 10s of millions of daily users, we would have completely different internal procedures and development practices: much safer and much slower.
I agree with this - my current main focus is effectively a CRM where I've exposed abilities for front-end devs to outright write SQL directly - as a shortcut when you need to get things done fast it can be fine.
But I've also never seen this done without getting horribly abused, and so I tend to lock things down gradually as a service matures or the team grows.
Then again, developers will try to work around it - I had one project many years ago where I on purpose introduced a very restrictive template language to ensure proper separation of content and logic, in large party because the templates were translated to 17 languages, and avoiding breakage was a lot easier the less logic there were in them...
Cue two of the developers trying to sneak in a tag to allow embedded Perl...
And this is why in general I don’t like ORMs, even my favorite ORM, Django’s. They hide from you the query complexity — and perhaps also the number of queries — that your ORM query produces. There are situations where a different ORM approach would yield similarly shaped data yet consumes orders of magnitude more or fewer resources. And this is without adding any new indices.
In general I don’t like giving anyone the ability to write queries unless I trust they understand the performance ramifications. This can be difficult to enforce because someone “on the outside” can always abuse your thoughtfully constructed set of access points you’ve provided by sticking them in nested loops.
Perhaps an answer is strict allocation of quotas outside the realm of assumed competence and good will.
That's why I only use orm with the simplest query. It helps so much if the queries are just select where, create update delete rather than composing the queries myself.
I totally agree. I much prefer tools like the now-deprecated Yesql for Clojure that provide for easy mapping of actual SQL queries to function wrappers for those queries. Also, given that the database is where your data model’s consistency should be enforced, stored procedures and views are your friends. The last fifteen years of web app frameworks and developer practices have abused/neglected RDBMS systems by regarding them as simple table stores. ORMS are a classic “now you have two problems” non-solution.
> GraphQL is great when your entities are complicated and interconnected with each other.
It's great for the frontend, but in this case it's awful for the backend.
> GraphQL allows you to do all of this in a single HTTP request, single SQL query and with 0 lines written by backend developer.
Yeah, right. Because that SQL query will just magically write itself. Especially if that ad-hoc GraphQL query requests extra fields (or doesn't request extra fields) or taps into data that' only available from an external service etc.
No, it can't, and it often won't. Just because you stumbled across a single application server that can do that doesn't mean it's true for GraphQL in general.
I think that these misconceptions a result of lack of experience/knowledge in graphic/databases and FP in general. I don’t see people writing assembly code trying to beat compiler optimizer very often, same thing here. We just need more competent engineers and a bit of time. If anything, we’ll move forward, to more conceptually complex protocol, definitely not back to the plain rest, that I saw many have nostalgia about.
> I think that these misconceptions a result of lack of experience/knowledge in graphic/databases and FP in general.
Which conception will magically convert an ad-hoc GraphQL query into "single SQL query and with 0 lines written by backend developer"?
> I don’t see people writing assembly code trying to beat compiler optimiser very often, same thing here.
No idea what you're talking about and how this is relevant
> If anything, we’ll move forward, to more conceptually complex protocol, definitely not back to the plain rest, that I saw many have nostalgia about.
As long as you pretend that GraphQL is magic that requires 0 backend work (but at the same time requires "more competent engineers and a bit of time"), then sure.
In thread you’ve pointed before there’s a link to postgraphie. Even without tweaks it already gives a decent code. With some little efforts you can optimize anything you want, score query complexity and etc. If you don’t want unpredicted performance, use persistent queries in production.
Nobody says backend work will magically disappear, but ignoring a generational improvement only because of job security concerns is insane.
The original post, if you’ll read it again, carefully, pointed out that you can compose a complex query in a single graphql query. And if you need this data, you have to get that data one way or another. What’s so hard about that? Now if you can make a single query to select that data, then great. In most cases there’s enough information to generate it automatically and efficiently and refine it if not. What’s not clear about that? Oh, maybe you have some magical and complicated infrastructure? Well, you have to query them anyway, right? It’s not automated you say? Sure, but you can always get insight from libs like Haxl, made by same Facebook. The magical database tool is a simple and comprehensible example (but still is brilliant in how well it works). The bottom line is that if dev team is capable of working with graphql, it’s just a better choice. Most of the projects I saw unfortunately are made in such a way that you hope they sticked to the good old Rest, because when you do that, use graphql as rest, the result will be disappointing. But come on, that’s the same as people migrating from react to vuejs bc it’s feels less alien or use mobx and other bi-directional storage instead of relay or redux, they’re obfuscating the problem for short-term benefit.
> The original post, if you’ll read it again, carefully
Literally says this, emphasis mine:
--- start quote ---
If you need to get user, then 5 of his posts, then 50 of comments for each post and then 100 reactions for each post, all connected by IDs in your DB, GraphQL allows you to do all of this in a single HTTP request, single SQL query and with 0 lines written by backend developer.
--- start quote ---
No. In general, it doesn't. There's a magical tool that they use, and they still have issues with it: https://news.ycombinator.com/item?id=25014918 So much for "single SQL with 0 lines of backend code" when you have "weird joins that we won't optimise for, and sooner or later there will be determined DDoSers who will figure it out"
> The magical database tool is a simple and comprehensible example (but still is brilliant in how well it works).
Yeah, this magical tool is only a tool, that works with a single database, for a single set of problems, and has to be constantly fine-tuned because you can't optimise ad-hoc queries.
But yeah, dismiss all that and just shout to the world: "REST sucks, GraphQL is so much better because we have this one single tool". The moment you step outside the limitations of that tool, you're screwed. But you haven't reached that point yet, so you consider yourself "competent".
> The bottom line is that if dev team is capable of working with graphql, it’s just a better choice.
This still has to be empirically proven by anyone without magical handwaving and dismissing any issues.
Omg, how hard is it to understand that any problem you attribute to graphql, will exist in rest. Every single one and more. Also, you can fine-tune any ad-hoc query, even in that magical tool, yeah. You know, your assumption of having a deeper expertise in that area is cute. I think you’ve imagined some dud who played with these magic tools and appointed himself an expert without a glimpse of understanding tech behind it. Well, that’s not true, but if it’s how you’re prefer to fin arguments, I’m fine. Otherwise, pls give me something, maybe some examples where you show how you have a better control of something or a better performance using rest over graphql? Because I don’t know if you understand, that graphql if just a glorified json generator. Yea, it’s much harder to design good resolvers, queries and limits, but it’s worth it. After all, if you have problems quering complex nested data (and you really objectively need it on a front end) in graphql, it can be only harder to handle correctly in rest, please, please prove me wrong.
> how hard is it to understand that any problem you attribute to graphql, will exist in rest
Ok, so then you agree that the person who said that this would allow you to solve these problems "with 0 lines written by backend developer." is completely wrong?
Awesome! Great. You now agree with the person you are responding to, that these problems cannot be solved "with 0 lines written by backend developer.", and that he was correct to critize this obviously false argument.
lol, no. but nice cherry-picking, btw. too bad the original (and unedited) post is still available.
# part 1
Let me break it down for you:
> (This example is pretty silly, but I have very similar and not silly examples that I just can't share because of respect for my employer's NDA).
So that's an example, an illustration. Like a metaphor, it works if other person is willing to communicate. It doesn't work if you cut and stretch it to fit your agenda. That's not an object of discussion, it is a pointer. Ok?
> If you just need to get one user object, it's not different from rest.
That simply says if you need some data, you have to get some that data. That statement is correct no matter what protocol you use. What would you do in rest, btw? Have a single endpoint, where you're trying to make a guess about what's the structure of this data would be? Having separate endpoints and have client cycle them to get what he needs? Limit his ability to traverse domain schema? In my opinion, these are f-off solutions. Because you're basically saying, that's the structure I know how to optimise on a backend, live with it. Look, it works great! What does it matter that you can't efficiently get your data? Not my problem, see, each of my endpoint is fast and simple.
> If you need to get user, then 5 of his posts, then 50 of comments for each post and then 100 reactions for each post, all connected by IDs in your DB, GraphQL allows you to do all of this in a single HTTP request, single SQL query and with 0 lines written by backend developer.
Yes, yes. That's exactly what will effectively work for that toy example. You actually can do that. Now, of course real-life is much more complicated and even if you're going to map gql to database, you don't want to map its structure as-is. It could be an interesting conversation on how to do that, but unfortunately, it's not.
But back on track, I believe the idea behind the quoted sentence is to illustrates, that you can do it, you can optimise a sequential and hierarchical query if that's possible. And in more complex cases, because you have a lot of information statically available and at query time you have a full structured query, you can know ahead its complexity and you know exactly what resolvers can be possibly executed to resolve the query. That gives you options:
1. Dumb and naive. Just call each resolver separately. That probably mirrors what would happen in rest. Because I'll repeat myself once again: you need the data, you have to get the data. In terms of transferring, transformation and querying, there should be zero difference.
2. A slightly smarter one. You can compose certain resolvers by grouping requests of same edges. That's fairly easy and should I explain why it's better than trying to do the same thing using rest, probably relying on intricacies of some query language a wise backend developer invented to solve a solved problem?
3. You can optimise for requests patterns. Yeah, that's right. You know that in order to satisfy gql client for such and such use-case, it needs certain data. So instead of making a separate endpoint with arbitrary degrees of freedom, you can have a better, cooler resolver that will perform your complex, which is exactly what you need. And if client requirement changes, he can extend that query and your optimised resolver will now work as a scaffold and additional resolvers will run on unexpected leafs. Which, again, you can optimise if you'll need. But that doesn't change the fact that client needs data. And he'll get it'll certainly get it anyway.
Now a reasonable combinations of these 3 options are required in reality. But that toy problem in topic illustrates exactly that: you can have a nice computer-assisted solution. And I don't think anybody doubt that in this particular case computer can generate a query almost as good as an average backend dev with "with 0 lines written by backend develo...
> If you just need to get one user object, it's not different from rest.
So then in this specific example, you agree that definitely it is not different than rest, and we cannot solve these problems "with 0 lines written by backend developer." then? Cool. Awesome. You agree with the person you responded to on that specific issue.
To be even more specific, it seems like you agree that it would not require "0 lines written by a backend developer" in order to do something like "taps into data that' only available from an external service etc.".
> you need the data, you have to get the data
Thats great that you agree with the other person that it does not require "0 lines" in order to do something like "taps into data that' only available from an external service etc.".
> But that doesn't change the fact that client needs data
Awesome. So then you agree with the person you are responding to, that you cannot, with "0 lines written by a backend developer" do something like "taps into data that' only available from an external service etc.".
Great. You are in agreement with him on that specific point.
It sounds like you agree with the original person, on the specific point that it definitely requires more than "0 lines written by a backend developer" to do something like "taps into data that' only available from an external service etc.".
Great. You are in agreement with him on that specific point.
But that’s absolutely not what the original example was showing. It was showing that even an dumb tool can do cool tricks on simple tasks. And that’s because you have an abundance of information about query and schema, so you can possibly do a more high-level reasoning about how to fulfill it.
There’re design flaws, but the direction is most promising.
It is still not really clear because you haven't really said yes or no.
But I am going to take a guess and say that you agree that:
it definitely requires more than "0 lines written by a backend developer" to do something like "taps into data that' only available from an external service etc."?
This is a yes or no question here. It should be pretty simple. Just say yes or no.
Since you keep misdirection though, I am going to assume that the answer is Yes, you agree with this original statement.
> Like I’m saying long live the backend job
So then you agree that it require more than "0 lines written by a backend developer" to do something like "taps into data that' only available from an external service etc.".
I was talking about the example originally provided, that had no data tapping with external services. That was a detail added by the guy I was replying to. idk why he decided it’s relevant there. If you want my yes or no answer, on is there an out-of-a-box solution for querying external services, then probably not. There can be, for some use cases, but I never researched them. And that’s actually not a bad idea to have some generic kick-in lib for that. So here, you have it.
I hope you understand that my issue is with the person who’s currently very busy with coming up with the infinitely recursive graphql query.
Alright, cool. So then you agree with that statement. Got it. Great. You are in agreement!
Furthermore, when you made this statement "Like I’m saying long live the backend job", it also is in agreement that there is definitely more than 0 backend lines required to solve something such as "if that ad-hoc GraphQL query requests extra fields", as that person originally stated.
I don't feel like I want to agree with that part, sorry. But I can admit I'm wrong if I had a counter-example relevant to that toy example.
I'm very confused on where you're going to with that.
> Because that SQL query will just magically write itself
Do we have any disagreement on whenever we can have a full computer-generated query for the case where there're a few tables connected by FKs which is not worse than anything a human could write? If not, can I have some hint on why?
You do not agree with the idea that it definitely requires more than "0 lines written by a backend developer" for most graphql applications to do something like support "ad-hoc GraphQL query requests extra fields"
Really? You actually don't agree with that?
You think that graphql is setup in such a way for most services, that it add "extra fields" to a backend service endpoint, that was not returning those "extra fields" in it before, and that it would require zero lines of backend code in most applications to add those extra fields to a backend endpoint, that was not returning those extra fields before?
No, because then I won't get anything from this conversation.
Please, tell me, what else can I say to make you use a practical illustration of your position constructed on top of original example? I believe it's the only form of productive communication left that is possible in current context.
So you think that graphql, for most applications, magically allows you to request an "extra fields" from a backend service, with zero backend work, that was not previously returning though fields? Really?
> use a practical illustration
I just told you the illustration. There is an additional field. That does not exist on a backend endpoint. And you think that graphql magically add that field, for most people, to the backend endpoint, with zero backend work?
That is a pretty simple and common practical example. Needing a extra field from a backend endpoint, that does not already exist in that backend service.
IE, to quote the original post, it would be to support "ad-hoc GraphQL query requests extra fields".
IE, an extra field that does not exist in the backend service.
That was the original post. And originally you disagreed with the original poster, when they claimed that such a thing would require more than "0 lines of code" on the backend, for most applications.
Ok, so you've failed to provide an example, I'll make you a big favour just this time.
> If you need to get user, then 5 of his posts, then 50 of comments for each post
That was the original database structure, right?
So we assume there're 3 tables, related by FK, right?
Now let's take a "magic" tool. It wasn't specified, which one or what db is used, so I'll take "postgraphile" and assume it's a Postgres. No problem here, right?
Now if I as an absolutely naive person, will run "postgraphile" and point it to my database schema, it will generate respective types and mutations, pretty much usable from the beginning. No problem here, right?
Now let's say I add an extra field to db schema to any table. Oh, dear, do I need to write a code? Let's try to restart it. Boom, it works. Right?
Need something more complex? Create a stored sql function (x: users|post|comment) => T that maps the data you need, restart a service and query your new field from your updated gql schema.
Alright.... now what if I were to tell you that most applications that use graphql are not using, or going to use, some singular magic tool, and therefore it does not get rid of all backend work, regarding adding new fields, for most applications?
So therefore, it is not applicable, for most applications, and the original comment was correct.
Because, as the original poster stated "Just because you stumbled across a single application server that can do that doesn't mean it's true for GraphQL in general."
In general, when talking about most graphql applications, that people use, the original statement is true.
So the original statement is true, for most people. Which was the other person's point.
I'd note once again that the statement was "in general".
Usually, when discussing large frameworks, and technical issues, that effect many people, we are mostly concerned with how it applies to the vast majority of people and applications.
You can't take an advantage of having an abundant amount of data about data sources, schema and query you're about to execute (in general)? The original example simply illustrates that if you have the right problem and understand it well, you can work on it a bit and make it look like magic. It says "G has some property, that lets us do X to solve problem Y", to what the other guys says "No, G doesn't have these properties, because you can't apply X to solve Z. And W." How dumb is that?
It's not an alternative to SQL in general and it's not a drop-in replacement for backend. Do you realise, that I can run graphql entirely in browser and make resolvers call the same rest api? That'll work pretty well. Or that also looks too problematic?
> we are mostly concerned with how it applies to the vast majority of people and applications
Applications – yes, people – no. In last couple of years I saw a few dozens implementations of graphql on a backend and I think only 2-3 were really good. The rest is usually a complete clusterfuck and I wish they didn't use it and never touched it. But that's also true for too many other things. So maybe you're right. Maybe if somebody realises that his competence isn't enough, it's better to stay away.
> It's not an alternative to SQL in general and it's not a drop-in replacement for backend
Oh, awesome! So then you agree with the original commentary then, that we cannot just replace all this with "0 lines written by a backend developer". Great.
Why don’t you just quote the word “by”? I agree with the word “by”. I fully support it and appreciate how precise and representative it is with respect to the topic. Thank you for walking that path with me, I am defeated by your debating skills and have no hope to recover.
He’s trying to make it like I believe in magic. Like I’m saying long live the backend job. Hell no, but it lets you to work with arguably better abstractions. And that posthraphile didn’t appear from thin air, it’s not a part of graphql, somebody wrote it.
# part 2
It feels that there are the following type of people zealously hating gql:
1. Those who for some reason don’t understand it. That’s obvious from the scope of problems they highlight. The problem of resolving the data is not really that hard. If someone’s complaining only about it, it can only mean that got stuck at the fist step: making it work. Those who got it work, talk about other problems, that are real: caching, for example. Or lack of URI and troubles with supporting linked data, structuring mutations, etc, etc.. Here, in other threads some people are saying it’s a FAANG only thing and big problems. Others say it’s a small-project scale and solution only to you problems. Make up your mind.
2. Those who would feel comfortable with backend if thinga stayed at cgi/Perl level. I actually have nothing against it.
> The problem of resolving the data is not really that hard.
Says the person who also wrote this: "Yea, it’s much harder to design good resolvers, queries and limits".
> Those who got it work, talk about other problems, that are real: caching, for example. Or lack of URI and troubles with supporting linked data, structuring mutations, etc, etc.
If you’ll keep cherry-picking this conversation will stop be entertaining. So yes, people who know what they’re talking about are discussing different set of problems that resolving data in general. I’m more and more convinced that you are not. And don’t twist my word, btw. I have nothing but respect for good old days guys and they are far from incompetent. But I f you think you belong to 2nd category, I want to point out that you can easily belong to both.
> any problem you attribute to graphql, will exist in rest. Every single one and more.
And then you go on to say:
> fine-tune any ad-hoc query
REST doesn't have ad-hoc queries, so no, this problem doesn't exists in REST
> it’s much harder to design good resolvers, queries and limits
So, it's much harder than in REST, but somehow REST has the same problems. Riiiight.
> After all, if you have problems quering complex nested data (and you really objectively need it on a front end) in graphql, it can be only harder to handle correctly in rest, please, please prove me wrong.
Once again: in REST you know exactly what your query will be. And even if it's hard to query and retrieve nested data, you can optimise that retrieval for that specific REST request you provide. With me so far?
GraphQL allows ad-hoc queries of unbounded complexity. This is the one and most significant problem that REST doesn't have. With me so far?
So, given all that, and given that you'r saying "it's much harder to design good resolvers, queries and limits" in GraphQL, how is handling complex data harder to handle correctly in REST?
It is not unbounded, unless you let it. Once again, at query time you have the full query. It’s not infinitely recursive. And if you split fetching the data by multiple endpoints and pretend your job is done, basically delegating the problem to your clients, what else can I say?
Let me quote: "Due to the nature of GraphQL it's easy to construct a small query that could be very expensive for the server to run".
And lo, and behold, it doesn't really have a solution against it.
So you have to either revert to basically REST with a predefined number of whitelisted queries, or pay for an experimental extension that attempts to calculate the cost of query.
> And if you split fetching the data by multiple endpoints and pretend your job is done, basically delegating the problem to your clients, what else can I say?
You can say something that actually shows that you know what you're talking about. Because you clearly have very little knowledge about REST and very sparse knowledge about GraphQL. You don't even know that unbounded complexity and infinite recursion are inherent in GraphQL.
Show me an example of how you make an infinite recursive query in graphql, I’ll wait.
And I can spell it to you again, you know structure and complexity of your query before you execute it. Feel free to ignore it and disguise ignorance behind I’ve pointed out by reverting that back on me. I’m asking a pretty simple questions, while you’re deflecting with an assumption that I need to prove my worth of your time, lol
I rarely engage in online discussions and only if know for sure what I’m saying.
> Show me an example of how you make an infinite recursive query in graphql, I’ll wait.
Literally in the example provided by postgraphile. It literally shows how to DDOS a GraphQL service by constructing a simple recursive query. It literally shows how even a few levels of recursion will break your server. It literally shows that by default GraphQL - and postgraphile - has nothing against this. So yes, you can increase recursion in the query ad infinitum, which is my point that you fail to understand.
> Feel free to ignore it and disguise ignorance behind I’ve pointed out by reverting that back on me.
Stop projecting. You can't even understand what the tool you mentioned does, and the problem the tool's own documentation describes.
Secondly, it's extremely easy to add a GraphQL validation rule that limits the depth of queries; here's an example of one where it takes just a single line of code: https://github.com/stems/graphql-depth-limit . This isn't included by default because there are plenty of solutions you're free to choose between, many of which are open source, depending on your project's needs. For most GraphQL APIs, persisted queries/persisted operations is the tool of choice, and is what Facebook have used internally since before GraphQL was open sourced in 2015. (Unlike what you state, this does not turn your API into a "REST API," it acts as an optimisation on the network layer and once configured is virtually invisible to client and server.)
> Firstly, GraphQL does not allow for infinite recursion; it is literally not possible to do infinite recursion in GraphQL
It's literally impossible to do infinite recursion anywhere because it's physically impossible to write down an infinite recursion.
However, if you look at the very example you provide on that page, you will see what I mean by infinite recursion. Moreover, you link to the Apollo page which literally has this example:
--- start quote ---
This circular relationship allows a bad actor to construct an expensive nested query like so:
Is 10000 infinite? No. Does it illustrate my point? Yes. Have you missed the point? Also yes.
> Secondly, it's extremely easy to add a GraphQL validation rule that limits the depth of queries
1. This statement is not even remotely true in general sense
2. It is not the default behaviour of any GraphQL implementation (because it's inherent in GraphQL)
3. The "extremely easy" solution for this particular case relies on an external package that needs to be added on top of something else. In your case it's not even added to postgraphile. It's added as an extra middleware to some other graphql library.
And that covers only one dimension: potentially infinite recursion. The other dimension is potentially unbounded complexity. For which the following is true:
1. It's inherent in GraphQL
2. Is not even solved by PostGraphile, except in an experimental paid package
3. The primary mode of mitigating this is disallowing arbitrary queries by providing only a whitelists of allowed queries (so, basically falling back to REST)
So in the end you end up piling more and more complexity on top of other complexities to arrive at a whitelist of allowed queries, ... which is basically just poorly implemented and over-engineered REST (well, REST-ish).
Honestly, no idea why you're fighting the facts of life that you yourself even document on your own product's pages.
So you gave me an example of a nested query that is not infinitely recursive and even admitted it. The one that as I said before you have an ability to easily identify before execution, just as any possible variations both in width and depth, from which I conclude that you lack some basic algorithmic knowledge or have troubles to apply them.
I know I’m arrogant, but yours is off the charts. Thanks for confidence boost!
Ping me when you’ll be able to show infinitely recursive query in graphql. Until that, I agree, there’s no point to continue, and have a good luck with that :)))
What prevents me from Ddosing your fancy rest api? Nothing if you do nothing about it first. Why do you assign omnipotent requirements on one technology, but not another?
If your front end is coded correctly, you know every query, their exact shape and complexity, so you can optimize for it and you exactly what you optimize for. If you let’s say have a public api, you’ll have more control than in rest, no less, because it’s easier to reason about what your api users need. It’s a foundation, not a final solution. You have to do some work to get something from it beyond mediocre, I thought that’s obvious.
This problem is solved with WunderGraph. We save all queries as stored procedures when you deploy your app. We disallow arbitrary queries in production so you can test and optimize all stored queries before deploying. This gives you the flexibility of GraphQL with predicable performance and security as if it were a REST API.
You just don’t get that you can apply limitations to graphql query not unlike you when you don’t allow to fetch a billion records from rest endpoint? This what that about? Because that’s a question of how, solvable.
You only need this flexibility during development. In production it's rarely the case you want to change a query without deploying a new version of the app. So there's no flexibility lost.
If you’re a backend developer, it’s just more work to do, unless you really make use of gql abstractions, they’re kind of more expressive than raw rest. For clients - instant exploitability, type safety, much more flexibility.
The reason why this is so powerful is that you can decouple frontend from backend with this pattern. If something is missing on a REST API you have to ask the backend developer to change it or create a new endpoint. In case of the former, the REST API gets bloated in case of many API consumers. Compare that to GraphQL and persisted Queries. The frontend developer can change the query themselves. If a change is required to the API they would still have to ask the backend developer to implement it. However, due to the nature of GraphQL other API consumers don't get affected by the change. All in all you get more for less.
The complexity will always live somewhere. Just because you are a frontend developer, and GraphQL magically makes your life easier, it doesn't mean that complexity is just gone. That backend you're so dismissive of is what powers your site/app, and it needs to be developed and maintained, and has to be performant etc. etc.
And yes, GraphQL makes backend significantly more complex, fragile, and prone to significant performance issues.
As someone who has worked on both front-end and back-end performance problems, moving a performance problem from the front-end to the back-end is a big win.
You have much more flexibility to solve problems on the back-end. On the front-end, you are fundamentally limited by the fact that you have to transfer all of the data and code to the client-side while the user is waiting.
To me that sounds like wilfully ignoring all the caching and concurrency opportunities you could have in addition to forcing all data through a single point of congestion.
At least caching can be solved somewhat, but not on the protocol level.
I think GraphQL is great for applications where there are no apparent caching or concurrency options.
If you look at the history you'd see that the people who invented GraphQL at Facebook were looking for a solution to a problem, not the other way around.
GraphQL support in Django is a dark beast. Graphene doesn't even support subscriptions out of the box, finding tutorials is difficult! For the DB we use it for the querying syntax is way better, but anything other than a basic query is black magic and crossed fingers.
I can see the promise of it, but getting there is so cumbersome. In our implementation it's supposed to provide a level playing field between devs working on a react app and devs working on internal sites that are django template powered. In a strict query sense, if you roll it with DRF auth and use an auth token in every query, it's very flexible for us.
But even things like partial mutations are fuzzy. The auth packages for it are immature, the integrations with channels is immature.
Graphql is a huge improvement over REST, and I don't see myself or any team I manage going back.
We provide legacy REST api's for some of our clients, but we are using Graphql internally.
Coupled with Hasura (https://hasura.io/) you have an extremely flexible, safe, and automated api that can consume multiple data sources and integrates very cleanly with serverless architectures.
A lot of the comments in this thread read like pure FUD, and I would encourage those of you on the fence to do your own research and evaluation before listening to the crotchety old devs (disclaimer: I am a crotchety old dev) here who are afraid their REST chops are obsolete.
I don't see how you back your statement with any real arguments. Why do you think it's an improvement? A lot of the time people argue GraphQL is better than REST, what they actually mean is that they didn't want a set of conventions but rather an opinionated framework that made the decisions for them. REST gives you a lot of freedom to do it wrong. GraphQL on the other hand makes some assumptions and decides a few things for you. This makes it easier to use if you don't want to dive into the complexity of designing and building proper REST APIs. The outcome will be more or less identical.
Because those conventions are rarely ever followed. That freedom to do wrong is not a perk for most organizations, and having an opinionated and consistent data layer provides a lot of value to large teams.
That coupled with GQL automation and type generation has literally taken months off of the development cycle for the last two products I've built. That has a real $ value that has led to actual success for those products. Not to mention that these API's are extremely flexible for the end user in a way that comparable REST api's could only dream.
I really like your answer. I think that's a very good argument if you want to convince someone to start adopting GraphQL. Do you have anything beyond that?
We have a pretty robust unified graphql api that handles millions of requests per second. Its has recently replaced siloed REST api's and now provides a common interface and RBAC for all of our data, which is housed in 5 different DB engines.
Previously most of the data was in MongoDB, so implementing GQL allowed up to regression test the api surface while migrating the underlying data. Remote schemas and persistent queries were pretty integral to that effort.
This is the video that made me install Hasura instantly and start testing it[0]. It was one of the few technologies that made me say there goes my weekend.
Its an amazing product with an equally amazing team behind it.
I am a happy customer and am in the process of converting the rest of my organization. It scales up really well and is one of the few pieces of tech I have used in the last few years that wholeheartedly recommend.
I don't think REST is well understood. Who does really understand the richardson maturity model? Who understands HATEOS? REST is a set of constraints. The implementation is up to the user. There's no requirement to document, it's optional. You can have an Open Api Specification, you're not forced to do so. GraphQL on the other hand is a lot more specific. It makes a lot of decisions for you. It's less flexible in that way but this also makes it easier to use.
Searched the article for the word "join", no hits. Strange: this is my personal top counter-argument to use GraphQL.
On my current project, we're using Graphana with Postgresql on the server and Apollo on the client. You create a new table in database, click a couple of buttons in Graphana admin panel, and the client now can query those tables, without a single line of code on the server! This part is awesome.
What is much less awesome though, is when you have a normalized database, and entities with many layers of links, and your client can generate GraphQL queries with so many crazy joins that will take your production database 30 seconds to complete — all while accessing public data, with no authentication required. So far, I haven't seen anybody figuring it out to DDoS our server, and every time this happens with real production queries, I get a fun index writing task.
However, just being able to run into database perfomance limitations by writing code on the client seems wrong. There's always going to be weird joins that we won't optimise for, and sooner or later there will be determined DDoSers who will figure it out and will be able to spam our server much more effectively with each query. I'm not yet sure what's the right way to alleviate this problem is, it's just strange that no one is talking about it.
Edit: I think I have been proved wrong by lukeramsden's comment below; or at least I should research this more before having an opinion on this matter.
A good page for this is Postgraphile's "Production Considerations" page [0]. Under "Denial of Service Considerations" it talks about a few solutions, such as statement timeouts, persisted queries, or query analysis. Choosing what to use may be quite project specific but there are available solutions.
Thanks for this! Immediately forwarded it to my team chat, this is incredibly useful. Turns out that they already researched these options and just haven't invested any time in them because it hasn't been a real production issue, so I probably should take my criticism back.
(Author here) If you want efficient database JOINs using GraphQL I'd always opt for Hasura. They've done a fantastic job solving this problem. This will almost always use the most efficient SQL you can get. If you want to extend this Schema you can use something like Schema stitching and you're good to go.
That's exactly what I'm using though! And for the most part, it's an awesome tool. But it still can't magically make resulting SQL query faster than it can be without tweaking the database itself.
Will hasura also help with the indexes, the most efficient SQL is usually the one which utilizes the indexes properly which still need to be setup to accomodate for each and every client side queries.
Besides hasura would have been great as a library but it's another api server you need to maintain on top of your existing one.
I think it would be a nice feature @tanmaigo should add to Hasura if it's not alredy there. Hasura could automatically detect slow queries and suggest indexes.
I see GraphQL and other tools created by FAANG companies being used all the time by 1-3 person teams. Their applications are often slow and poorly made. I say that because initially I felt like maybe I wasn't being "professional" if I didn't use these tools, but actually using their applications reassured me that I was going in the right direction.
I see people use GraphQL as the new ORM. I see it used by people who don't have that much experience with databases. I see it used by people who have nothing much to do. It is sometimes about cost requirements. You can just spin up one of those automatic graphql servers that creates the entire backend for you. Sure it doesn't have any logic or security or performance, but it was quick to get up and going and the client is not experienced enough to notice in the beginning. It is often used with Apollo client, so these inexperienced developers then have all kinds of caching issues due to the automatic caching the client does that they don't really understand.
I see it having an application at FAANG scale, where there are teams of front end and back end people, and front-end people can just create the UI without talking to the back-end people. I see it being used at places with enough scale to have multiple graph databases, not SQL databases, or multiple types of databases that need to be unified.
That isn't where it is used in most cases though. It ends up being a very limited version of SQL that is slow. I think it would be good for maybe a public API.
While you're right I see another trend as well. Multi national Fortune 500 companies with many many sub organizations and hundreds or thousands of engineers who try to find a way to scale APIs for them. Not saying REST is no solution to them but GraphQL, especially with schema stitching and/or federation can definitely help in this case to organize the API landscape.
I use GraphQL all the time in conjunction with PostGraphile https://www.graphile.org/postgraphile/ and let me tell you, it's definitely not slow. If anything it is very fast. But just like REST or anything else, if you do a poor implementation you will get a poor result: garbage in, garbage out.
Yes exactly! GraphQL would be great for a huge company with multiple front end and backend teams that are a challenge to communicate between. It standardizes and simplifies things for that massive organization and alleviates the pain of communicating API changes across such a big organization.
If you are one small to medium sized team. Or honestly even 2 small to medium sized teams, GraphQL is overkill. The people working on the API for your frontend are either right next to you, or even you yourself. So there’s no need to introduce this big backend framework with a strict API. There’s just little to no process or code quality benefit for small teams. Unless someone on your team is absolutely terrible, and that terrible person is going to cause problems anyway.
I get your point. But to be honest, why is a well designed REST API with a developer portal and amazing documentation not capable of delivering exactly that? Take Stripe for example. Would Stripe be as successful as it is with GraphQL? If yes I believe they would have had to build a lot of additional tooling to make it work. The same they did for their REST API by the way. They invested a tremendous effort into their documentation and developer portal. I guess that's the essence of a successful API strategy. Whatever technology you choose, you must invest in the developer experience, hence build good documentation, example use cases, etc..
> I see GraphQL and other tools created by FAANG companies being used all the time by 1-3 person teams.
GraphQL is touted as a technology which saves developer time by avoiding the need to develop REST APIs, and instead just expose your database to the world and let your frontend just get whatever data it needs.
No wonder you're seeing small teams using it. It's not because of FANG, not because of cargo cult development, not because of incompetente. It's because small front-end teams don't spend their scarce resources on areas where return of investment is limited.
> GraphQL is touted as a technology which saves developer time by avoiding the need to develop REST APIs, and instead just expose your database to the world and let your frontend just get whatever data it needs.
Where are you seeing this? There are a couple of solutions that follow this model (e.g. Hasura, Postgraphile), but it's not an approach recommended by any of the creators of GraphQL, or the bulk of its users.
This is the part I was focusing on, sorry if there was confusion. For context, I've been working with GraphQL since June 2015, so I'm pretty intimate with the topic.
It's worth noting that those slogans you quoted are from graphql.com rather than graphql.org. The latter is the official site, the former (.com) is owned by Apollo and isn't official in any capacity -- something I personally find to be an extremely questionable situation. GraphQL's actual slogan is "A query language for your API".
I’m the maintainer of PostGraphile and I also don’t approve of “just expose your database to the world and let your frontend just get whatever data it needs.” PostGraphile is a tool to help you to rapidly build performant and secure GraphQL APIs that follow many of the GraphQL best practices out of the box. It is not a “run and done” solution, you do have to put a little effort in to build a decent API but we give you the tools to achieve this in a fraction of the time of rolling your own, and probably with better performance also. Our extensive documentation is peppered with advice on how to craft your API, not to expose more than you need, not to expose complex filters (instead adding specific filters the frontend needs), how to include/exclude things, how to add in additional fields, types, remote content, etc. Our users are generally very happy, we’re just not very good at marketing ;)
Most of the negatives you're observing seem to be a consequence of people not knowing how to use GraphQL well. This is definitely a problem worth solving, but it's also not a problem with GraphQL per se -- if you snapshot the usage profile of any high growth tech, you'll see that at any given moment in time most of the people using it don't have a lot of experience with it, that's just what growth looks like.
My opinion here is somewhat unusual -- even with the GraphQL world, but I think you can get benefits from using it even at teams of just 1 engineer. But you _definitely_ don't need to be anywhere close to FAANG scale for it to be worth the investment.
> Most of the negatives you've observing seem to be a consequence of people not knowing how to use GraphQL well.
People who know how to use GraphQL aren't likely to be dissuaded from using it well by a blog post or some internet comments, so this is an argument in favour of telling people “if you have to ask, GraphQL isn't the right tool for the job”.
Perhaps. But there's an angle here which is there's a VC goldrush of GraphQL ecosystem solutions, many of which (IMO) probably aren't good ideas. So there's a lot of marketing push towards solutions which represent many of the negatives the post I was replying to highlighted.
I think GraphQL actually _is_ the right tool for many of the jobs people are using it for (API layer for 1st party clients), but they're often using it poorly due to many of these tools having slick APIs that let you be productive alarmingly quickly -- you only feel the pain much later.
I used GQL on projects before. I never used those 'ready-made' tools though. All the resolvers were written by hand and the SQL queries as well (in the ORM specific language).
GQL works well when you have unstructured data that 'links' to other or in places where you need to query data in various different ways, with different joins that REST doesn't help (or you end up creating a querying language on top of your REST endpoints anyway (/clients/?age>2&link=business,jobs&business.broke=false&etc etc etc)
Then you need to do this for pretty much every REST endpoint that may need this functionality. With GraphQL the server knows how to fetch the individual entities along with the filters, and create a nice graph of it for you (and you can optimize the resolvers if you dont want to have a lot of DB calls).
Saying people are using GraphQL as the new ORM is the same as I saying people are using Ruby on Rails (and their scaffolding) as the new low-code solution.
I don't get the love/want for GraphQL clients. Sure they are nice to get started but like ORMs they are needed until you hit a certain level of Team/Project scale.
That said it's good to see a counterpoint to the GraphQL push. With gql, gRPC, etc, it's a great time to be working with APIs.
Have you ever hit a point where you scaled beyond a point where GraphQL clients were usable? Apollo, urql etc. look quite flexible to me, I've never had such issues.
I can’t ever go back to REST from something like Hasura. It’s just too easy, too fast, and too flexible.
Some of the comments about performance and security are obviously from people who haven’t taken the time to do a proper deep dive. I’m sure there were similar arguments against REST from the SOAP crowd.
You're right if you're directly exposing your Databse-driven-GraphQL API to the client. If you use GraphQL to power your REST APIs this is less of an issue. On the other hand, tightly coupling your database to a client doesn't always have to be a bad thing. If you outscale a single Postgres Database with Hasura you can add read replicas. If that still doesn't work you can add Yugabyte to the mix to scale further.
It can do, however you can also use views, custom query functions for whole queries or for specific columns, custom mutation functions, or simply extend the schema at the Node application level to do a lot more than just the structure of the DB tables. For me it just means I don't have to write any code other than the schema to simply expose CRUD actions with filter and sort and such things - the escape hatches have been perfectly adequate for more complex behaviour.
We use jsonrpc 2.0 over websockets, typescript + runtime type assertions using functional combinators at the i/o boundary, it's very fast, bi-directional, type safe, pleasure to work with, easy to optimise (rpc call duration is easily captured), we know exactly the number of connected clients, it's easy to inspect outgoing buffer sizes, debounce notifications to do adaptive "throtthling" for people on slower networks etc. Above all, whole communication is uncomplicated and straight forward, lightweight. We tend to maintain client library by b/e team (maybe ~90% of code by b/e devs) for anything non trivial. The best documentation you can get is typed + jsdoc described library that you can just use. It is up to date. It's cheap to add new calls and notifications, it's easy to change apis where typescript guides you through changes required etc.
This is more or less the approach I'm taking with WunderGraph. There's just one exception. I'm not using websockets but simply a HTTP2 stream. Browsers have limitations regarding how many tcp connections you can open to the same origin and for each tab/window and websocket connection you have to open a new tcp connection. HTTP2 on the other hand can pipeline, depending on your browser, up to 200 streams over a single tcp connection, regardless of the tab or window. I've written a post on the topic: https://wundergraph.com/blog/deprecate_graphql_subscriptions...
"(...) The infamous 6 connections per host limit does not apply to WebSockets. Instead a far bigger limit holds (255 in Chrome and 200 in Firefox). (...)".
We do single connection per session (tab/window), there's no need to have more.
There are simple reasons GraphQL is prefered to REST.
It's a spec and not a architectural approach, which makes all GraphQL APIs more uniform than all REST APIs.
It comes with a type-system that makes code generation really easy and allows for tools like Graphiql, which are orders of magnitude better than what most REST docs deliver.
Can this be done with REST?
Sure, just use something like OpenAPI.
Problem is, most REST APIs don't use such tools/specs, but most GraphQL APIs do.
From my experience (most with github’s graphql api), graphql is phenomenal for get queries as you can get a big chunk of things in a single request exactly as you want.
Github’s graphiql explorer was a joy to use and has saved me hours. For fetching a graph of nested data, graphql absolutely shines giving you fast responses of only the data you need.
For mutations though, graphql is a giant pain in the ass. We wrote a bunch of things using graphql mutations and after two months reverted all mutation code back to using REST api. GitHub was flakey, some things didn’t have error responses. Mutations would screw up encoding “ character and it was just painful.
REST api was much more deterministic and easier to work with. POST/PATCH/PUT/DELETE map well.
I wish graphql didn’t invent its own quirky language and stuck to good ol json.
In my experience graphql wasn’t worth the hype. There is a lot of over complication. We’ve got a lot more production success sticking to the basics.
NOTE: we were interfacing with github’s graphql api from python. Outside of js, graphql tooling is sparse and sometimes non-existent.
Do you have ideas on how we can make mutations work better? What's missing? What could have helped in your situation? Would really appreciate your input.
> GitHub was flakey, some things didn’t have error responses
That just seems like API problem rather than GraphQL problem. The equivalent would be REST API that just returns 500 without any additional info. You can be lazy in both stacks, I don't think any one of them particularly prevents you from being lazy about handling errors / typing useful error messages.
> Mutations would screw up encoding “ character and it was just painful.
Interesting, haven't heard about this. Also cant come up with how this is related to GraphQL, as you are just transferring string, just like you would do with REST. It seems more of an problem with some proxy/grapql framework layer that didn't handle the character correctly?
> REST api was much more deterministic and easier to work with. POST/PATCH/PUT/DELETE map well.
I don't see this as a big win, in GraphQL you just have `somethindUpdate` `somethingCreate` `somethingDelete` mutations, it is true that it is up to you to keep the naming consistent but nothing really that would be big trouble, or win for the REST.
> I wish graphql didn’t invent its own quirky language and stuck to good ol json.
If they did that you would end up with some quirky JSON query and schema syntax that would look like json schema or the mongo query schema. It is true that if you do new syntax you lose some json tooling that could be used (eg syntax highlight) but I don't see that much stuff transferable to the problems that GraphQL is solving.. so you would still end up with bunch of custom tooling on top, and when you need that you might as well go the way they did, with new syntax, that is not as quirky as whatever mongo/json schema like thing they would come up with.
> There is a lot of over complication.
This is definitely true and one of the most overlooked things by GraphQL evangelists, the "additional complexity layers" are non negligible.
Not sure if that's relevant - but were you aware that you can pass GraphQL inputs as plain JSON in variables?
In the vast majority of cases, you don't need to build mutation inputs (or anything else, really) in GraphQL syntax. Python requests library should be more than enough if GraphQL is being used the right way.
466 comments
[ 29.8 ms ] story [ 1169 ms ] threadFor example, we have done small rewrite of Apollo Android library and achieved like 100x performance boost simply by writing as it should be written. Literally very minor changes and better DB.
Typesafe codegeneration? Still feels very beta anything your could find.
Compare it to something like grpc that have strict typed clients for almost anything.
What's so amazing to me is that it is really easy to spin up a server that talks graphql in any language. But there is no client support.
And hand crafting queries is a million times worse than reading the rest documents
Oh, you want to get a list of items by owner, you can do that but you'll also have to paginated the inside and outside list. And the client will have to follow these pages while also having a deep understanding of your model.
Without good client tooling, graphql is a nightmare.
How is pagination worse than the REST equivalent?
I guess I could see a case for client side caching based on IDs, but unless you couple this with subscriptions thats kind of brittle.
With rest, you can only paginate that particular call. You cannot really paginate different results in that one call. At most you can do is say get the list of objects at this endpoint. And that is far easier to grok than graphql's pagination in even the simple case.
I mean, just look at the official guide on this: https://graphql.org/learn/pagination/
And that only covers a simple use case!
Graphql allows you to paginate several collections in the same call, but you certainly don't have to. You can do just like REST and do one at a time.
Where did you get this idea that REST in any way dictates how you do pagination?
As far as I know, JS clients Lokka and Urql are pretty small and cloud be easily ported to a different language.
My point remains, why write queries when you can query endpoints and write filters easily without having to learn a new query language?
Better to just provide a nice, typesafe client library generated from OAS.
?
We are using hasura (which is written in Haskel), I'm interested in dgraph.io (which is golang).
I had terrible experience writing graphql-service in typescript. I finished it but I did not liked it's strange behaviour and bloated docker image size. I rewrote it in 2 days with graphql-go/go and then it became OK: predictable behaviour and ~16Mb docker image. I'm thinking about rewriting another service too.
On client side I used: - python client `gql` - .NET `graphql-dotnet` - Apollo client - graphqurl - js client from hasura team
The worst impressions are from Apollo. Starting from their documentation. IDK why they explain everything starting from UI.
https://grpc.io/blog/state-of-grpc-web/ is from early 2019
Edit: Since I got a bunch of questions that seemed to be the same. The few times I've used a graphQL API i was expected to know which attributes I was requesting per object, instead of just getting them all and figuring it out later. That was my main concern. I want to find an endpoint, get a list of objects without knowing what will be in them and start throwing stuff at it. I usually do this in python using jupyter, so when I'm finished exploring I have working code that just needs to be refactored a bit to fit into wherever it's going to go. For me, this workflow is usually faster than even finding the documentation on most systems.
But yeah i apologize for my early morning crankiness, I was really complaining about a few specific implementations of GraphQL that I found frustrating. And to be fair these specific companies I'm thinking about also had annoying REST/SOAP APIs in the past and are now touting GraphQL as a sort of silver bullet.
Graphql coupled with graphiql is extremely easy to explore. So easy in fact that we have replaced all of our api documentation with graphiql instances that we provide to our clients.
I would encourage you to learn more about the tooling before posting FUD.
Maybe for a toy project you can just jump in and start hacking, but then who really cares what tech you decide to use?
Interacting with systems like this for a decade has conditioned me to just try it out first, and then look up what i need to know if i'm having trouble, or need to optimize.
We built a machine learning platform[0] with additional functionality [near real-time collaboration, long-running notebook scheduling, automatic model tracking and deployment, etc.]
- [0]: https://iko.ai
It's really good for tab completing a new library I'm trying, especially if said library dynamically creates attributes with their own dynamic attributes.
I was doing that in ipython before the notebook was released, but what really won me over in the notebook was parsing data that didn't want to be parsed. I could have different cells that set a blob of data to different states, and try tweaking regexes or splits or whatever without having to restart or save intermediate files. And if I mess something up I just rerun the appropriate cells to get me back to where I was.
My biggest complaint is the way it handles automatic parentheses and quotes, it's just always a bit off.
[0]: I've received some remarks about the fact I say "near real-time" and not "real-time". We have too many people from an Electronics Engineering background, including myself, on the team to dare use the term "real-time" for a web service. That's why we say "near real-time".
It is very easy to provide additional graphql schemas that expose business logic as a remote schema.
You'll likely never be in a situation where over-querying via a non-granular REST call will ever be an issue worth optimising around.
If you're shipping multi-megs of JS to a client don't then pretend that micro-optimisating the API call waterfall is your KPI, it's just disingenuous at best.
At best it's a band-aid around dysfunctional inter-team working.
I'm not saying it's enough, far from it. Bit it can be a very liberating 1st step.
While I agree with your beginning sentence, the one I quoted doesn't sit well with me. It would be good to remember that not everybody has 100 Mbits fiber or 5G download speed.
We all saw the data on how milliseconds affect user retention then proceed to completely forget about it once building our apps.
I think we can do better.
GraphQL creates a data graph that powers the UI, REST creates a database that you can query on the UI and you have to compose it all together and manage.
Then you don't share many of the reasons GraphQL was originally created for. Act accordingly.
Web API contracts are primarily routes and request/response data structures. This allows front end and backend concerns to be separate which allows a lot more flexibility over time for both front end and backend developers. From my limited knowledge of GraphQL, this is still possible but more work than just exposing your db schema types/DTOs.
I'm not sure that the query layer solves team collaboration and prioritization problems.
Adding brand new capabilities to a system (or refactoring existing ones) will usually requires changes to the GraphQL layer, but this is only a subset of frontend work. Iterating on what already exists also represents a lot of development time.
Ultimately the thing that speeds up teams, again in my experience, is predictability not flexibility. If you tell someone they have a RESTful API they know exactly how to work with it, document it, etc. GraphQL which is shiny, new, and used by in-vogue orgs is fine, you can use it to get the job done, but I don't believe that it warrants much praise.
> because they don't need to ask the API team to change an endpoint
Bollocks. What happens is you need some field implemented in the microservice or DB that your GraphQL layer talks to. This task gets tossed into your ticket system, gets managed by half a dozen managers, and weeks to months later you finally get the field you need and can finally bubble it up through your fancy toy API.
> GraphQL creates a data graph
does anyone even know what a graph is today? Serious question.
In a company you often have APIs geared for client apps, and then internal APIs between services. But rarely anyone develops good APIs for backoffice. And then you have an admin interface struggling to retrieve the data it needs from a dozen different API calls.
Slap a simple GraphQL server in front of these dozen calls, and you have a more streamlined development for internal tools.
It's a good instinct to be suspicious of new technology. But I have personally seen, many times, what REST APIs can grow into - unless you are very, very careful, "get user/1" can turn into god objects with every field under the sun, non-optional. I've seen `users/l` be over a megabyte with (eg) comments, friends, comments of friends, likes, likes of friends, and every other thing the front end team ever asked for. GraphQL solves that.
Yes, it can be avoided with strict, diligent design. But it often isn't. GraphQL solves the whole class of problem. And that's why I like it, despite my mistrust of "new hotness" technology.
I've always held a strict rule where The R in REST stands for Resource (which isn't true). There's a user, an Invitation (and not an invite action on user, nor a state:invited or invited_at on user). there's a Session. There's links that clients follow, and everything is as small as possible. I really don't see how REST encourages God objects.
GQL solves this problem elegantly by allowing you to specify the data that you need in a single request.
That is just one example, there are many many others that you can google if you are actually interested.
Fair point.
But I ask my question again, differently worded: how does Graphql solve this? Why does GraphQL solve "many requests" and why can't you solve or avoid this in REST.
My endpoints also have fields that will only be sent if you specifically request them.
This alone makes it impossible to get backend to return god entities with dozens of relations without explicitly specifying them.
If `User` had `groups` and `groups` had `permissions`, then I can do:
My system has its limitations however. It can't do relational constraints like GraphQL or renaming of fields, but it is likely the 20% that gets you 80% of the way.https://lucene.apache.org/solr/guide/6_6/common-query-parame...
Well, within one of our frontend apps, someone wrote a "GetUser" query fragment, wrapped it in a react hook to make it easy to use, and now anytime anyone anywhere wants to get a user, even with one field, they're getting 100+ fields they don't want. Anytime someone needs a new field on a user, they don't create a new query; they just add the field to that "GetUser" query.
Now, I've told several GraphQL advocates that setup (in our local community and online), and unfailingly they balk at it. Well, you're doing GraphQL wrong, everyone makes mistakes, you should be more selective, etc etc etc. I think that's fair; being more specific sounds like a good pattern.
Except, we are not certain the performance wouldn't suffer should we move everything to more selective queries. The issue is caching. If you have ten queries each requesting one field, the cache can't saturate until after ten network requests. But, one mega query, and now the remaining nine queries can just pull from the cache. Sure, the mega query takes longer than one mini-query, but its not longer than ten mini-queries.
I only outline this to say: GraphQL is not a magic bullet. Every single thing you can do which would ruin a REST API is also possible in GraphQL. REST API responses naturally evolve into god objects. GraphQL APIs solve the god object issue server-side by saying "god objects are fine", then push the responsibility of not abusing it onto the client (and it should be obvious, the client is the worst place to solve almost every problem, but that's another topic).
GraphQL is easier and better for some things, far harder for other things. At the end of the day, its no worse than REST. I don't recommend it, but that's only just because its new; unless a new technology offers some very easy to express, tactile benefits for your business, just wait for it to mature. When you get down to it, GraphQL's benefits are definitely not tactile, but they're still there, and I think over time it will evolve into something very interesting.
What you described is absolutely correct, except it is only the case if we cache by query. If we cache by objects and fields, none of those issues you described become relevant, and caching by object/field (as opposed to caching by query) in general seems like a better practice imo, aside from certain very specific scenarios.
In fact, it seems like the official GraphQL docs recommend that approach as well [0].
0. https://graphql.org/learn/caching/
If, instead, you have QueryC which does User { firstName, lastName }, but two usages of it (QueryC1/QueryC2), after QueryC1 requests, QueryC2 can use the cached results. This works whether you're doing Query/Operation level caching or Field/ID level caching. The former example works in neither. And QueryC is trivially faster than QueryA+QueryB because of network overhead.
This isn't necessarily an issue with GraphQL (and, I thought I was clear about this, but: I'm not against GraphQL). Its a behavior of both typical REST implementations and GraphQL. And, to be clear, GraphQL's out-of-box caching story is more powerful than any REST implementation I've seen short of hyper-engineered FAANG companies, because it enables really powerful field/ID level caching across multiple queries. But it doesn't work in this case.
The point is that its still very immature. Even the thought leaders (Apollo being the biggest one and worst offender) write these blog posts filled with Best Practices and Recommendations that often convey horrible advice and flat-out misrepresent GraphQL's actual advantages compared to REST. GraphQL solves a lot of REST's problems; it does NOT solve REST's "god-object" class of problems, like the grandparent comment suggests; and it introduces many new classes of problems that remain unsolved in the ecosystem because of how immature it is (one great example is OSI L7 inspection in many tertiary tools a typical SaaS app has. Many products like Datadog, CloudFront, AWS ALB, etc are capable of doing some really cool and powerful stuff out-of-the-box just by inspecting standard HTTP headers. REST is basically just standard HTTP; your resource is in the path, query parameters, http headers, its very standard. GraphQL is not, so many of these tools don't work out-of-box with GraphQL. People are catching up, but again, its immature).
The backend performance you could gain is kinda spurious anyway. We're talking about N requests being coalesced into 1 mega-request; I would rather clients send me N small requests, not 1 mega-request. Horizontal scaling is easy to set up and quick to do in real-time; vertical scaling is harder.
And I think, while a solution like this is interesting in the domain of "you've got two sibling components rendered at the same time who's queries could be combined", that's not exactly the issue I described a few comments up. Caching really doesn't enter into play here; it would not be measurably faster to just issue one mega-request for one component and let the other wait for the cache (which is, in the end, what we're talking about). I mean, it saves one network request, but 90% of a network request is just waiting on IO, and if there's one thing Javascript is really good at, its sitting around and waiting. It can wait for dozens of things at a time.
The issue is more specifically surrounding two components being rendered at different times. Imagine a User Preview card which displays a user's first name; the user clicks on that card, which takes them to a new page, the User Profile, which displays both their first and last name. Short of using a God Query for the Preview which covers a broad set of common user fields, like firing a shotgun and hoping you've got the cache saturated for unknown upcoming components, this situation will take two requests. The shotgun approach is what we do, and what many companies do; it works, but its imprecise. It can hurt the performance of the leading components which pulled the short stick, if that God Query gets too big, and as an application evolves you're gonna forget to keep that God Query updated with new things you may need.
This problem is enticing because it feels like there should be a solution, and we just haven't, as a community, found it. I think GraphQL, at its core, has the capability to solve this; its not like REST which is so undefined and hazy that any solution to something super-complex like this would only work in the domain of one company's "way of doing things". I hope one day we can figure it out, because I suspect that a general, easy to use way of preemptively saturating a cache like this would be a MASSIVE performance boost to every GraphQL client that's ever been written.
The existence of a God Response / God Object / or just a generally horrific and coupled system strikes me as a particularly human induced problem which no specific technology can actually fix.
I'm a big fan of the saying "complexity has to live somewhere" and I think that's exactly what GraphQL is doing: moving the complexity to another layer.
Some people also want an agile api surface so they can iterate quickly, GQL is an excellent solution to that problem.
It is also an excellent solution for: - client side caching - unified RBAC - service stitching / microservice hell - api documentation via graphiql - decoupling FE dev from api dev - api automation - typed api surface
The list goes on.
To say that GQL is a just a band aid for bad leadership is nonsense, and discounts the very real reasons that many many experienced teams are switching to it.
I would encourage you to re-evaluate your position as if you voiced those opinions in an interview with basically anyone I know you would quickly get passed up in favor someone that actually knows what they are talking about.
Ha. Now we’re introducing threats. Don’t agree with my technical opinions? You’ll never work in this town again! Funny, funny stuff.
Also, React is a hype stack now?
> React is a hype stack now?
Yeah, kinda. You definitely need some sort of front end framework, but I feel like there should be something better than react. I use react every day and it’s fine, but I’m waiting for something else to come and take it’s dominant position.
I build apps for living and hiring a svelte dev is not going to happen. Stick to react and go hiking on the weekends with the guys in your svelte meetup.
React and GraphQL are extremely hyped. People build static HTML pages with React because... React. People use GraphQL APIs because... GraphQL.
These days the first thing every JS developer I've seen asks is: can we use GraphQL (which in fact they mean Apollo)?
I'm not saying it doesn't have its use-cases and merits, but it's very much hype tech.
Edit: typo
If you can't see the positive benefits of a new type technology, then you might be passed up for someone else more open-minded.
But yes, I agree that you should be critical of all new tech, and not just accept it blindly because FANNG says so...
Conversely, if you are also incapable of seeing the drawbacks, then you are a bad engineer who also deserves to be passed up for someone else.
I would encourage you to re-evaluate how you react to opinions that diverge from your own, especially in an interviewing context. GQL is not a panacea, and candidates should not be discounted because they understand this.
"At best it's a band-aid around dysfunctional inter-team working."
I would absolutely discount a candidate for having a moronic opinion like that.
Picking a non-sexy, non-scalable, "wrong" technology that does nothing more than solve the actual requirements at hand is a rare and amazing quality for engineer to have imo.
Everyone wants to build infinitely flexible, infinitely scalable machines using the most rapid iteration tools possible as though that's what "engineering" is. But sometimes... all you need is a REST API. Sometimes you need GraphQL. Sometimes, all you need is to stuff data in a bucket somewhere and call that an "integration point". All solutions have trade offs. Pretending otherwise, or faulting others for weighing those trade offs differently than you, is silly.
Non sexy "wrong" tech is exactly that. Pick smart tools that do the work for you so that you don't have to babysit your teams choices and micromanage every project.
I have weighed the trade offs, and it is literally my job to identify the problems that come from them.
I am glad you understand now.
That is exactly the kind of problem solver I like to work with. Most of the time, “boring” tech will solve the problem cheaper, faster and as reliable and scalable as any shiny new tech. I work with GraphQL, REST APIs and even JSON RPC APIs on a daily basis and when you truly use those tools, you get to know where they really shine.
Is everyone you know solving FAANG problems? If they are not are they emulating those FAANG companies tooling because they expect to be one or work at one in the future? Or is it a type signaling?
There is this over tooling over scaling wave going on.
Most startups fail because in their limited investments they over tool and under sell.
Do you work at a startup or a FAANG?
I don't see the tradeoff that people are talking about, with GQL there has been nothing but upside.
If you are a person who is not capable of seeing drawbacks as well, then you would also be a bad engineer who should also be passed up for other candidates, who are more capable of evaluating both the benefits and drawbacks of certain solutions.
Simply point Insomnia at the base url and it’ll introspect the schema and provide typed query auto completion. No dozens of requests to different endpoints with different query parameters than can only be kept track of by having the api docs open on a second screen.
I'm not being flippant. If you're already using REST tools such as Postman and every caching tool in existence (browser, http proxy, etc. etc.) then GraphQL tossing it all out is the exact opposite of "ergonomic."
The caching story in GraphQL is a joke. What the browser gives you for free with GET caching takes weeks and months of fine-tuning and tweaking and head scratching with something like Apollo. Then you'll probably try decreasing the payload size (there's a third-party solution for this), or batching requests together (guess what... there is a third-party solution for this too). The amount of tooling and implementation work GraphQL needs to get up to par with built-in REST is pretty incredible.
I work at a small startup. We use a REST and Redux architecture. It's worked very well for us, but we're starting to hit some pain points. As we look to re-architect, our list of challenges pretty much mimic the challenges GraphQL looks to address. These aren't scaling issues or "big company issues". In my opinion, they're core issues with every client-server code base.
* Client Data and Statement Management
* API Coordination and Versioning (even more complex if you have a public API)
* Payload Management and Relational Data (it can be very expensive to pro-actively return embedded/dependent data, so you need to manage it somehow)
* Caching and De-deduping
* Typing and Data Interfaces between Client/Server
* Error Management (not that hard to standardize, but still something you need to account for)
* Pagination, Filtering, Sorting, etc.
This isn't to say that GraphQL is bad or anything, but there are definitely some gotchas that are important to evaluate before diving in.
> I work at a small startup.
This means you can afford a lot of technical debt, even such technical debt as might be incurred by GraphQL (as argued by the post and many people in this conversation).
The concerns you've posted are certainly valid, but GraphQL is not the only (or even necessarily best) way to address them.
If you have a huge engineering staff like FB, then perhaps it's better to just "move the complexity to server side", but for most businesses that not what's going to happen. What's going to happen in practice is DoS galore.
I'd rather take on technical debt related to our product features than to load us up on fundamental networking and caching issues.
EDIT: Sorry, a bit of a rambly post, too tired and emotional to rephrase.
I will say, though, that "fundamental networking and caching issues" sounds very... weasel-wordy, if you see what I mean? It's not very concrete about what the actual problems you might experience would be. (Yes, latency and huge numbers of requests are issues, but is it really an issue until you get big enough?)
Almost all successful applications in existence until about 2018 (or so? Not sure exactly when GraphQL was invented) has done just about fine. If we're talking about a brand new type of application which couldn't have been done without it, then fine. If not... well, we're not talking about technical limitations.
I truly do see the appeal of GraphQL for developers, and especially the fast decoupled iteration that it enables, at least theoretically. The thing is that when you need more data on the client, you still have to add that data on the server... somewhere. It's great that the client can choose the overall "shape" of the data, but that doesn't solve the problem of the data not actually being on the server.
Sure, but that's only one advantage of GraphQl. Personally, I'd use GraphQl even for the smallest of apps. With statically generated sites, you can forgo a back-end server and just setup a GraphQl instance. It's a one-time cost to learn, and then you easily setup your APIs and if you are using React/Vuejs, it's even easier to integrate with your API.
GraphQL has never made sense to me for anything beyond toy or small-scale projects.
Being able to very quickly connect a series of tools and tech together in a way that is selective of the data being moved around saves me money and time, period. That matters.
If inter-team communication isn't a hard problem in software development, why are we even talking about API technologies?
If inter-team communication wasn't that hard, you could just email pc and ask him to email you a snippet of Ruby to process a credit card payment.
I do agree a lot of software is built just for the sake of software - there is loads of needless complexity in things. But GraphQL is not that imho.
I'm a developer of my own projects for fun. I don't work in tech. My frontends are on iOS / Android / the web with Typescript. So my confusion is from a perspective without expertise.
I started with REST via Django and a few others, and now I've switched to GraphQL. I love GraphQL over REST backends due to the type automation tools such as GraphQL Code Generator and query tools like Apollo. Also being able to construct a query and access children via one request is super nice. For example my old REST APIs call for a post, then get pictures for that post, then get comments for that post, then gets the username and other user data for the owner that made the comment. It's four requests. My GraphQL requests just get them all in one customizable request. Post can contain pictures and comments and all their properties. Comments can contain the owner of the comment and all its properties to include things like username.
The result is a typescript object that is strongly typed and has all the data I need. Before GraphQL, in REST, this would be four requests, three of which are in series (post -> comment -> owner to get username). I know I could make a custom REST API to do the same thing, but it was just so easy in GraphQL, I didn't have to worry about it.
I'm not working in teams, I'm not creating a super large backend, it's not complex projects... so I don't know what I don't know.
But what am I missing? Maybe not everyone needs / uses the typing I do? That's the big benefit for me. Maybe not everyone cares about being able to query children (or create children via a nested create)? Maybe these things were easier than how I was doing it in REST?
You're suffering under Dunning-Kruger.
For example, what you described about making 4 requests with your 'REST' API, you didn't have to do that. YOU made that terrible API. That's not a feature of REST, but you seem to have mixed the two up in your head.
REST: Any time there is a new "view"; you need to go to your server and write a new endpoint.
GraphQL: You can stitch data together however you want; as long as that data is defined.
So for example if I need name of someone and the url of their children; querying it alone is enough with GraphQL whereas with REST either I need to fetch multiple times or write a new endpoint that serves both together.
Resource is not what you think it is. The conflict you’re talking about doesn’t exist.
That might be the case. Those things (such as returning children - and generally crafting a custom endpoint for specific use-case) are indeed very easy in my language/framework of choice (ASP.NET with a little help from LINQ).
I also get automatic generation of client-side data classes and strongly typed functions that encapsulate endpoints on the server using a small code generation framework that literally took 2-3 days to write (it's really not that complex).
It absolutely is the bottleneck in almost every web app that relies on Ajax fetches. The latency is an absolute killer.
On every app that I've optimised, I have to get people to stop going with their gut and look at the traces (both synthetic and real-user). People generally think they should be optimising their JS execution. But in fact the most important thing is usually sequencing loading correctly, followed by minimising JS bundle sizes.
Modern browsers are getting really good at parallelising loading and parsing JS and other resources. But if you're whacking some fetch in there that happens as a result of JS execution then you're generally looking at a wasted 300-500ms for most endpoints/device combos.
As a backend engineer, I publish a schema of all the available data - the frontend can fetch it in any shape it prefers. Web UIs and mobile UIs often have different views, so they want different data, and fetching it in one request or many is up to the preference of the UI.
I don't have to build different REST endpoints presenting some data in a different shape for performance reasons or because different applications wanted to request the data in a different way.
As a frontend engineer, all the data is often already there unless I'm building some new feature the backend doesn't understand yet. I'm free to refactor my application without bothering changing the REST API - and GraphIQL lets me inspect the api and mock queries for how I might fetch the data for a given view.
It's a cleaner contract to let different people get their job done with less fuss - game changer.
I've def been in this situation before. But I agree that it it is not the norm
I think this post is very good at stating why the particular post it’s referencing (“Why GraphQL” in the Apollo docs) isn’t a full picture overview, and it succeeds at that very well, but I think it doesn’t go on to expand on these views just as much as I’d like to.
If we look at popular comments by the GraphQL community on this it isn’t hard to find that “the quickest & easiest client is to just fetch a GraphQL API” (similarly said quite frequently) and that’s an excellent point.
But going on to say:
> However, you should always consider the cost of adding a GraphQL client to your frontend.
This is definitely true, but as a creator of another GraphQL client I’d say that there are major benefits as well, the main selling point of Apollo, Relay and urql (for the latter this is optional) being that you can utilise a normalized cache.
But these tools often provide great frameworks to solve some of the problems that are stated to be woes with GraphQL, like persisted queries, subscriptions, file uploads, etc. So they’re a great starting point to dip into multiple parts of the community and get out-of-the-box solutions for your problems.
And generally I’d say that sums up GraphQL: it’s not novel or anything new. Instead it combines a lot of ideas into a solid community and ecosystem. With tools like Swagger or gRPC it’s easy to see how any part we look at for GraphQL isn’t novel.
What is great is that the exact set of problems it solves it does so with a larger (and growing) community and a standard that encompasses multiple of these solutions.
Finally, I’d say again, GraphQL clients and servers aren’t “all of GraphQL,” Apollo isn’t GraphQL (although they’ve made themselves synonymous with it) and hence there are different tools, clients, and libraries to create GraphQL servers, clients, and interact with GraphQL APIs. As a user you’ll still have to choose, but a lot of the good parts come from agreeing on one language and standard that allows for introspection and the ease using which we interact with these APIs on the client-side, from simple HTTP calls to more complex caching clients.
I’d say that’s completely fair still, just wondering. I’d also say I understand the carefulness and stance on “smart clients,” i.e. normalized caching, which is why this isn’t a default in urql, but without it I think the discussion here is much more nuanced.
It’s so to speak much easier to rely on an argument with a smarter client and the Apollo ecosystem, than the rest. Anyway, I like your approach with Wundergraph so I’ll definitely check it out!
Another thing is mutations - does WunderGraph support mutations at all yet? Security for those is also even more important, as you might want to restrict what entities you can attach to the entity you're creating etc.
I guess the root of my question is how much business logic can you achieve with WunderGraph itself? It's probably not something that's necessary if I really think about it, if it just handles the authN and then passes tokens with claims nad user IDs to the data sources, Hasura/Postgraphile et al can handle the row-specific authZ and business logic, and then WunderGraph can just be the BFF for each app client. I'd still definitely use it in that setup, as the generated clients and federation subscriptions would be a marked improvement over Apollo for me.
Mutations are fully supported. When generating clients all we do is treat mutations like POST requests and queries and subscriptions like GET http2 streams falling back to http1 chunked encoding.
WunderGraph doesn't want to contain business logic. We are the front door, making everything secure and establishing a stable contract between client and server. We mediate between protocols and we map responses so that every party gets data in the format and shape they expect. Other than that, if you want to add custom logic just run a lambda with any of the supported protocols, e.g. GraphQL, REST and in the future gRPC, SOAP, Kafka, RabbitMQ, etc. and we do the mediation. But as were the middleware layer I'd try to not put business logic into this.
That said I'd love to get in touch and discuss how WG can add value for you.
But what it does do is constrain. Now, constraints are great. They’re always a great tool to introduce new innovations. What I’m ultimately thinking is, how much do you bring to the table compared to persisted queries and tools like GraphQL Code Generator and the added flexibility that comes with those tools?
Genuine questions of course, not criticism
Next we're able to execute the persisted query on the edge using etags for low latency.
WunderGraph adds the capability to use @stream & @defer on top of any existing GraphQL or REST API. You don't have to change anything on your existing GraphQL server. This works especially great with Apollo federation. WunderGraph is a replacement for Apollo gateway. We support federation with subscriptions, @defer and @stream, another unique feature to WunderGraph. The generated code gives you simple to use hooks, in case of react, to fetch data or streams.
Finally the generated code is authentication aware. WunderGraph has its own OIDC server. Generated clients know if authentication is required for a specific persisted query. This way a query will wait until the user authenticates and then fire off.
I think this should be enough. I don't want to get too much into the details as there are a lot more benefits.
But I don't think it addresses why I'd want a "smart" GraphQL client: normalized caching on the client.
Say I have a dashboard where multiple panels on a given page make their own requests, since the panels are shared between many pages. But they share some objects. If I get updated data in a request from one panel, I'd like to see that update in all panels, without triggering more requests.
Side note that a magic layer to have each of those components combine their requests into one would actually hurt performance, since it's better to load the requests in parallel. And manually merging them into one would be quite a chore.
Absolutely true! When I worked on this at $prevCo, it was tricky and sometimes caused bugs, unexpected behavior, and confused colleagues.
I will say that a proper implementation of a normalized cache on the client must have an ~inherent (thus generated) understanding of the object graph. It also must provide simple control of "whether to cache" at each request. Most of the problems we experienced were a result of the first constraint not being fully satisfied.
My impression is that Apollo does a good job on both of these but I haven't used it so I can't say.
I'll also note that the approach of "when one component makes an update, tell all other components on the page to refetch" sounds like a recipe for problems too – excess server/db load, unrelated data changing in front of users' eyes (and weird hacks to prevent this), etc.
Of course, with the wundergraph architecture, it sounds like answer to these questions would simply be to load a given table only once per page – which means no more defining queries on the "panel" components in the dashboard, for example.
All tricky tradeoffs! The right answer depends on what you're building. The Wundergraph approach sounds pretty cool for a lot of cases!
Does it lead to greater complexity somewhere, and all the issues around making that complexity bulletproof? Sure. But the user experience is so viscerally different that some will demand it. I think it’s admirable to work on getting that complexity correct and properly abstracted so that it can be re-used easily.
I think Jens Neuse is making two important observations about GraphQL:
1. GraphQL's single URL/endpoint [1] is possibly an anti-pattern
2. ETags are important for Cache-Control and Concurrency-Control on REST endpoints
The concept of prepared statements is useful for my SQL-centric brain. WunderGraph effectively creates a REST endpoint for each prepared statement (GraphQL DML). Like prepared statements in SQL, WunderGraph uses query metadata to determine the types of input parameters and the shape of the JSON response.
Kyle Schrade makes an important point about canonical GraphQL queries: response payloads can be reduced by filtering JSON fields, similar to SQL projection (i.e. the columns specified in the SELECT clause). It seems that WunderGraph can potentially support both approaches by allowing optional GraphQL queries on each REST endpoint that can be used to filter the endpoint specific JSON response.
[1] https://graphql.org/learn/serving-over-http/#uris-routes
It might be a useful exercise to prototype an online shopping site using WunderGraph.
[1] https://en.wikipedia.org/wiki/Faceted_search
[1]: https://www.onegraph.com
One of the biggest selling point rarely come up is that you get the API docs for free through the playground. No more Swagger bad API
Real proper documentation is not just a list of endpoints and their attributes but explanations of those as well as other things.
So how is that the "biggest selling point" of GraphQL when it's not even new in the ecosystem?
I've written a lot of swagger docs over the years, GQL is a massive improvement.
With REST, I know how the data is being presented, and can craft DB queries with focused indexes to ensure it's as fast as possible.
If we're talking about highly interconnected objects in an API, it would be expensive (from a DB point of view) to arbitrarily add indexes in the long shot case that someone may use a selector on that property.
Equally, when data is highly interconnected, by designing an API that focuses on particular consumption patterns, I'm able to add custom functionality, pre-processing, or highly customised queries/indexes to ensure the data is read as fast as possible.
Poor performing API's are bad for the consumer, bad for the database, and bad for the art of data.
There's a balance between centralization and independence in software models that is so hard to balance right.
MicroServices, GraphQL, and Docker Swarms are examples of technologies that, if done right, can be enabling, and if done wrong, will pull the ship to the bottom of the ocean.
The "graph" part - GraphQL seems to want you to build these big interconnected webs of types. But there isn't good tooling on the backend to deal with resolving relationships between types efficiently. Someone decides they need user.friends.pets.names, and now my backend code is doing 3 DB round trips because my GraphQL server lib doesn't understand it can turn the relationship between the types into a JOIN. I decide that's no good and the query needs to be faster, the alternative is I have to do the JOIN every time even if the client didn't actually request friends. And if I'm going to overfetch from the DB, might as well send that data to the client anyway?
My experience was that because of how backend GraphQL servers are written, it becomes very challenging to reason about performance. It's hard to think about how your nice type resolvers are going to interact, and fan out into some nightmare n+1 query problem performance pit.
I know there are some better tools than this, which I sadly haven't tried...
Tools like Dataloader solve the n+1 problem quite effectively, and they've been around for about 5 years, making it a solved problem for the overwhelming majority of GraphQL's open source existence. If you look at the examples I wrote in this article (https://andrewingram.net/posts/optimising-graphql-request-wa...), in the waterfall charts each "call" is roughly equivalent to one simple (and usually easy to optimise) database query. I don't want to unduly trivialise the work in getting Dataloader properly integrated, but I will say it doesn't take a lot to start seeing the fruits of your effort.
And the second thing is that solving something by slapping an unknown library into the stack instead of using the DB tools which are readily available out of the box doesn't make much sense IMO.
Its much easier to define SLA's and manage your traffic profile/platform when the load of each "query" is definitely quantifiable and granular - unlike a GraphQL query.
Then people come to me and say - well you can pre-can your GraphQL queries so that you know which queries are going to be run therefore you have known performance. At which point I say - why not just make a specialised REST endpoint with that query inside it?
I see it as a good backend-for-frontend adapter technology where a bulk query can be sharded into individual smaller ones using core backend services for large use-case specific views. If a query uses too much resources then the GraphQL server and/or a client ID can be rate limited by the backend servers, etc. Which is why I think its mainly a JS thing to date IMO - it doesn't solve many core problems for most backends - it solves typical front-ender dev's issues who can't/don't want to write server side code.
One good example - 'users' and 'comments' tables with natural relationship. 'Comments' grow to unreasonable size and split into different tables, fresh comments stay in 'comments', old comments moved to another database with cheaper storage. With REST it is easy, I get a query like 'get user's A comments from X till Y'. I have to deal with two dates and based on that figure out how to fetch data.
With GraphQL I can get query like this but also something like this 'get user's A comments from user.signup_date.year till user.signup_date.year + 1'. I suppose I would have to deal with query AST to figure out if it queries archive dates or not. This sounds like 100x more complicated compared to REST.
https://stackoverflow.com/questions/45842544/graphql-objectt...
In REST, I can send the columns and know what I am going to get back. All the queries need not be defined to start with.
Especially if the scalar never includes other data from the graph (other objects) describing the custom format with scalars is just fine.
GET clients [client 1, client 2]
for each client
Now think you can join with business, jobs, invoices, employees, etc etc, and tell me how to do this in rest without basically recreating a query language?Then you write the resolvers that parse that. Pretty much as I would expect you to do it in REST.
(mentioned it in another post, I created a no-code tool that did this, for random data and entities created by the user per tenant/app, so I know the issues with GQL, but I can assure you, doing the same with REST was 10 times harder (api started as REST and moved to GQL after 6 months)
Douglas Crockford taught me a really valuable lesson here... in Javascript: The Good Parts he had something directed at the haters of Javascript, that stuck with me. But I think it applies here too. GraphQL and REST are tools/patterns that have pros and cons. All tools have pros and cons. Why would you get mad at a hammer for not being good drill? Because that is what people do in our industry and it's silly.
I tried two years ago to write an article with this in mind, and the conclusion I came to in [0] is that it is an abstraction. Nothing more, nothing less. It's up to the individual to determine whether that abstraction makes sense to them.
Haters are always gonna hate, and I do appreciate your taking the time comparing and contrasting the two. Too often articles that say "Hey wait a minute here, we might be drinking the koolaid for x" come across as contrarian and spiteful. I think you managed to keep a respectful tone while asking important questions. Thank you :)
0: [link redacted]
Junior devs neither understand the business nor the technology, but they get promoted to senior dev anyway after 6 months of bootcamp and 2 years on the job.
Because Hammer, Inc. and it's community sold your CEO on the wonders of having a hammer which was handed to you for the task of drilling holes.
The tooling around Apollo is pretty good, and that’s great but so many of the “why GraphQL” arguments are either short sided, assume you are doing REST badly, or imply you are an organization that is much bigger and has scaling problems most of the projects I’ve worked on do not have. So far I am very happy I went back to a REST API.
Oh and here’s another REST benefit: when working on my REST API I spend most of my time thinking about good API design and testing practices. When working with GraphQL I spent most of my time figuring out how GraphQL ecosystem libraries worked. I would much rather spend my time thinking about how to do the job well than how to glue together an ecosystem of tools that someone else designed. Admittedly this is a very subjective line to draw, for instance I loved Rails and some people make the same criticism of Rails that I make here for the GraphQL ecosystem.
(This example is pretty silly, but I have very similar and not silly examples that I just can't share because of respect for my employer's NDA).
I don't particularly want that to be easy, because I've too many times had to clean up the consequences.
If you have a team where everyone understands the database implications, then awesome. In that case this consideration may not apply.
I have a couple of issues that I worked on that started exactly like this: front-end developer implemented a feature based on GraphQL, but when we deployed this feature, we quickly disabled it after receiving alerts from production database, and re-enabled it back only after backend developer (me) went and worked on database indexing.
But for my team, at the current point of the project's development, this scenario is a net positive overall, because we're exactly in "move fast and break things" mentality, which suits our product and our place in the market. If our project would require a lot of 9s, or worked with very confidential data, or had 10s of millions of daily users, we would have completely different internal procedures and development practices: much safer and much slower.
Also, I wrote about this exact problem in another thread under this post: https://news.ycombinator.com/item?id=25014918
But I've also never seen this done without getting horribly abused, and so I tend to lock things down gradually as a service matures or the team grows.
Then again, developers will try to work around it - I had one project many years ago where I on purpose introduced a very restrictive template language to ensure proper separation of content and logic, in large party because the templates were translated to 17 languages, and avoiding breakage was a lot easier the less logic there were in them...
Cue two of the developers trying to sneak in a tag to allow embedded Perl...
In general I don’t like giving anyone the ability to write queries unless I trust they understand the performance ramifications. This can be difficult to enforce because someone “on the outside” can always abuse your thoughtfully constructed set of access points you’ve provided by sticking them in nested loops.
Perhaps an answer is strict allocation of quotas outside the realm of assumed competence and good will.
It's great for the frontend, but in this case it's awful for the backend.
> GraphQL allows you to do all of this in a single HTTP request, single SQL query and with 0 lines written by backend developer.
Yeah, right. Because that SQL query will just magically write itself. Especially if that ad-hoc GraphQL query requests extra fields (or doesn't request extra fields) or taps into data that' only available from an external service etc.
And once you go you go beyond toy examples on minuscule data, even those magical tools immediately run into problems: https://news.ycombinator.com/item?id=25014918 (note: this is by the author of the comment I replied to) and https://news.ycombinator.com/item?id=25015173
Which conception will magically convert an ad-hoc GraphQL query into "single SQL query and with 0 lines written by backend developer"?
> I don’t see people writing assembly code trying to beat compiler optimiser very often, same thing here.
No idea what you're talking about and how this is relevant
> If anything, we’ll move forward, to more conceptually complex protocol, definitely not back to the plain rest, that I saw many have nostalgia about.
As long as you pretend that GraphQL is magic that requires 0 backend work (but at the same time requires "more competent engineers and a bit of time"), then sure.
Nobody says backend work will magically disappear, but ignoring a generational improvement only because of job security concerns is insane.
That was literally what was directly stated in the original comment I responded to.
> but ignoring a generational improvement only because of job security concerns is insane.
Ah yes. People who have only one database with a magical tool try to berate people with significantly different requirements.
The original post, if you’ll read it again, carefully, pointed out that you can compose a complex query in a single graphql query. And if you need this data, you have to get that data one way or another. What’s so hard about that? Now if you can make a single query to select that data, then great. In most cases there’s enough information to generate it automatically and efficiently and refine it if not. What’s not clear about that? Oh, maybe you have some magical and complicated infrastructure? Well, you have to query them anyway, right? It’s not automated you say? Sure, but you can always get insight from libs like Haxl, made by same Facebook. The magical database tool is a simple and comprehensible example (but still is brilliant in how well it works). The bottom line is that if dev team is capable of working with graphql, it’s just a better choice. Most of the projects I saw unfortunately are made in such a way that you hope they sticked to the good old Rest, because when you do that, use graphql as rest, the result will be disappointing. But come on, that’s the same as people migrating from react to vuejs bc it’s feels less alien or use mobx and other bi-directional storage instead of relay or redux, they’re obfuscating the problem for short-term benefit.
Literally says this, emphasis mine:
--- start quote ---
If you need to get user, then 5 of his posts, then 50 of comments for each post and then 100 reactions for each post, all connected by IDs in your DB, GraphQL allows you to do all of this in a single HTTP request, single SQL query and with 0 lines written by backend developer.
--- start quote ---
No. In general, it doesn't. There's a magical tool that they use, and they still have issues with it: https://news.ycombinator.com/item?id=25014918 So much for "single SQL with 0 lines of backend code" when you have "weird joins that we won't optimise for, and sooner or later there will be determined DDoSers who will figure it out"
> The magical database tool is a simple and comprehensible example (but still is brilliant in how well it works).
Yeah, this magical tool is only a tool, that works with a single database, for a single set of problems, and has to be constantly fine-tuned because you can't optimise ad-hoc queries.
But yeah, dismiss all that and just shout to the world: "REST sucks, GraphQL is so much better because we have this one single tool". The moment you step outside the limitations of that tool, you're screwed. But you haven't reached that point yet, so you consider yourself "competent".
> The bottom line is that if dev team is capable of working with graphql, it’s just a better choice.
This still has to be empirically proven by anyone without magical handwaving and dismissing any issues.
Ok, so then you agree that the person who said that this would allow you to solve these problems "with 0 lines written by backend developer." is completely wrong?
Awesome! Great. You now agree with the person you are responding to, that these problems cannot be solved "with 0 lines written by backend developer.", and that he was correct to critize this obviously false argument.
# part 1 Let me break it down for you:
> (This example is pretty silly, but I have very similar and not silly examples that I just can't share because of respect for my employer's NDA). So that's an example, an illustration. Like a metaphor, it works if other person is willing to communicate. It doesn't work if you cut and stretch it to fit your agenda. That's not an object of discussion, it is a pointer. Ok?
> If you just need to get one user object, it's not different from rest. That simply says if you need some data, you have to get some that data. That statement is correct no matter what protocol you use. What would you do in rest, btw? Have a single endpoint, where you're trying to make a guess about what's the structure of this data would be? Having separate endpoints and have client cycle them to get what he needs? Limit his ability to traverse domain schema? In my opinion, these are f-off solutions. Because you're basically saying, that's the structure I know how to optimise on a backend, live with it. Look, it works great! What does it matter that you can't efficiently get your data? Not my problem, see, each of my endpoint is fast and simple.
> If you need to get user, then 5 of his posts, then 50 of comments for each post and then 100 reactions for each post, all connected by IDs in your DB, GraphQL allows you to do all of this in a single HTTP request, single SQL query and with 0 lines written by backend developer. Yes, yes. That's exactly what will effectively work for that toy example. You actually can do that. Now, of course real-life is much more complicated and even if you're going to map gql to database, you don't want to map its structure as-is. It could be an interesting conversation on how to do that, but unfortunately, it's not. But back on track, I believe the idea behind the quoted sentence is to illustrates, that you can do it, you can optimise a sequential and hierarchical query if that's possible. And in more complex cases, because you have a lot of information statically available and at query time you have a full structured query, you can know ahead its complexity and you know exactly what resolvers can be possibly executed to resolve the query. That gives you options: 1. Dumb and naive. Just call each resolver separately. That probably mirrors what would happen in rest. Because I'll repeat myself once again: you need the data, you have to get the data. In terms of transferring, transformation and querying, there should be zero difference. 2. A slightly smarter one. You can compose certain resolvers by grouping requests of same edges. That's fairly easy and should I explain why it's better than trying to do the same thing using rest, probably relying on intricacies of some query language a wise backend developer invented to solve a solved problem? 3. You can optimise for requests patterns. Yeah, that's right. You know that in order to satisfy gql client for such and such use-case, it needs certain data. So instead of making a separate endpoint with arbitrary degrees of freedom, you can have a better, cooler resolver that will perform your complex, which is exactly what you need. And if client requirement changes, he can extend that query and your optimised resolver will now work as a scaffold and additional resolvers will run on unexpected leafs. Which, again, you can optimise if you'll need. But that doesn't change the fact that client needs data. And he'll get it'll certainly get it anyway. Now a reasonable combinations of these 3 options are required in reality. But that toy problem in topic illustrates exactly that: you can have a nice computer-assisted solution. And I don't think anybody doubt that in this particular case computer can generate a query almost as good as an average backend dev with "with 0 lines written by backend develo...
So then in this specific example, you agree that definitely it is not different than rest, and we cannot solve these problems "with 0 lines written by backend developer." then? Cool. Awesome. You agree with the person you responded to on that specific issue.
To be even more specific, it seems like you agree that it would not require "0 lines written by a backend developer" in order to do something like "taps into data that' only available from an external service etc.".
> you need the data, you have to get the data
Thats great that you agree with the other person that it does not require "0 lines" in order to do something like "taps into data that' only available from an external service etc.".
> But that doesn't change the fact that client needs data
Awesome. So then you agree with the person you are responding to, that you cannot, with "0 lines written by a backend developer" do something like "taps into data that' only available from an external service etc.".
Great. You are in agreement with him on that specific point.
It sounds like you agree with the original person, on the specific point that it definitely requires more than "0 lines written by a backend developer" to do something like "taps into data that' only available from an external service etc.".
Great. You are in agreement with him on that specific point.
There’re design flaws, but the direction is most promising.
But I am going to take a guess and say that you agree that:
it definitely requires more than "0 lines written by a backend developer" to do something like "taps into data that' only available from an external service etc."?
This is a yes or no question here. It should be pretty simple. Just say yes or no.
Since you keep misdirection though, I am going to assume that the answer is Yes, you agree with this original statement.
> Like I’m saying long live the backend job
So then you agree that it require more than "0 lines written by a backend developer" to do something like "taps into data that' only available from an external service etc.".
Awesome. You agree with this statement.
I hope you understand that my issue is with the person who’s currently very busy with coming up with the infinitely recursive graphql query.
Alright, cool. So then you agree with that statement. Got it. Great. You are in agreement!
Furthermore, when you made this statement "Like I’m saying long live the backend job", it also is in agreement that there is definitely more than 0 backend lines required to solve something such as "if that ad-hoc GraphQL query requests extra fields", as that person originally stated.
I'm very confused on where you're going to with that.
> Because that SQL query will just magically write itself Do we have any disagreement on whenever we can have a full computer-generated query for the case where there're a few tables connected by FKs which is not worse than anything a human could write? If not, can I have some hint on why?
Really? You actually don't agree with that?
You think that graphql is setup in such a way for most services, that it add "extra fields" to a backend service endpoint, that was not returning those "extra fields" in it before, and that it would require zero lines of backend code in most applications to add those extra fields to a backend endpoint, that was not returning those extra fields before?
Please, tell me, what else can I say to make you use a practical illustration of your position constructed on top of original example? I believe it's the only form of productive communication left that is possible in current context.
So you think that graphql, for most applications, magically allows you to request an "extra fields" from a backend service, with zero backend work, that was not previously returning though fields? Really?
> use a practical illustration
I just told you the illustration. There is an additional field. That does not exist on a backend endpoint. And you think that graphql magically add that field, for most people, to the backend endpoint, with zero backend work?
That is a pretty simple and common practical example. Needing a extra field from a backend endpoint, that does not already exist in that backend service.
IE, to quote the original post, it would be to support "ad-hoc GraphQL query requests extra fields".
IE, an extra field that does not exist in the backend service.
That was the original post. And originally you disagreed with the original poster, when they claimed that such a thing would require more than "0 lines of code" on the backend, for most applications.
> If you need to get user, then 5 of his posts, then 50 of comments for each post That was the original database structure, right? So we assume there're 3 tables, related by FK, right? Now let's take a "magic" tool. It wasn't specified, which one or what db is used, so I'll take "postgraphile" and assume it's a Postgres. No problem here, right? Now if I as an absolutely naive person, will run "postgraphile" and point it to my database schema, it will generate respective types and mutations, pretty much usable from the beginning. No problem here, right? Now let's say I add an extra field to db schema to any table. Oh, dear, do I need to write a code? Let's try to restart it. Boom, it works. Right? Need something more complex? Create a stored sql function (x: users|post|comment) => T that maps the data you need, restart a service and query your new field from your updated gql schema.
ffs, read before you write.
So therefore, it is not applicable, for most applications, and the original comment was correct.
Original comment I've reacted to:
> Yeah, right. Because that SQL query will just magically write itself.
Oh, just did, sorry
> Especially if that ad-hoc GraphQL query requests extra fields
Just did, whoops
parent comment: > GraphQL allows you to do all of this in a single HTTP request, single SQL query and with 0 lines written by backend developer.
Just did, ha-ha! Does it allow it? Yes, just as illustrated.
> I were to tell you that most applications that use graphql are not using, or going to use, some singular magic tool
That's not relevant and you know it.
> So therefore, it is not applicable, for most applications, and the original comment was correct.
Critical logic error, no intelligent lifeforms detected.
It is pretty relevant actually.
Because, as the original poster stated "Just because you stumbled across a single application server that can do that doesn't mean it's true for GraphQL in general."
In general, when talking about most graphql applications, that people use, the original statement is true.
So the original statement is true, for most people. Which was the other person's point.
I'd note once again that the statement was "in general".
Usually, when discussing large frameworks, and technical issues, that effect many people, we are mostly concerned with how it applies to the vast majority of people and applications.
You can't take an advantage of having an abundant amount of data about data sources, schema and query you're about to execute (in general)? The original example simply illustrates that if you have the right problem and understand it well, you can work on it a bit and make it look like magic. It says "G has some property, that lets us do X to solve problem Y", to what the other guys says "No, G doesn't have these properties, because you can't apply X to solve Z. And W." How dumb is that?
It's not an alternative to SQL in general and it's not a drop-in replacement for backend. Do you realise, that I can run graphql entirely in browser and make resolvers call the same rest api? That'll work pretty well. Or that also looks too problematic?
> we are mostly concerned with how it applies to the vast majority of people and applications
Applications – yes, people – no. In last couple of years I saw a few dozens implementations of graphql on a backend and I think only 2-3 were really good. The rest is usually a complete clusterfuck and I wish they didn't use it and never touched it. But that's also true for too many other things. So maybe you're right. Maybe if somebody realises that his competence isn't enough, it's better to stay away.
Oh, awesome! So then you agree with the original commentary then, that we cannot just replace all this with "0 lines written by a backend developer". Great.
Says the person who also wrote this: "Yea, it’s much harder to design good resolvers, queries and limits".
> Those who got it work, talk about other problems, that are real: caching, for example. Or lack of URI and troubles with supporting linked data, structuring mutations, etc, etc.
Those who understand the problems with GraphQL talk about this, too. If only you were able to see what they are saying. For example: https://news.ycombinator.com/item?id=25014009
So,
- much harder to design good resolvers, queries and limits
- problems with caching, for example. Or lack of URI and troubles with supporting linked data, structuring mutations
And yet, people who talk about these problems are somehow "incompetent developers who pine for the good old days of cgi/perl". Impeccable logic.
And then you go on to say:
> fine-tune any ad-hoc query
REST doesn't have ad-hoc queries, so no, this problem doesn't exists in REST
> it’s much harder to design good resolvers, queries and limits
So, it's much harder than in REST, but somehow REST has the same problems. Riiiight.
> After all, if you have problems quering complex nested data (and you really objectively need it on a front end) in graphql, it can be only harder to handle correctly in rest, please, please prove me wrong.
Once again: in REST you know exactly what your query will be. And even if it's hard to query and retrieve nested data, you can optimise that retrieval for that specific REST request you provide. With me so far?
GraphQL allows ad-hoc queries of unbounded complexity. This is the one and most significant problem that REST doesn't have. With me so far?
So, given all that, and given that you'r saying "it's much harder to design good resolvers, queries and limits" in GraphQL, how is handling complex data harder to handle correctly in REST?
It is unbounded by default. And the tool you're so enamoured with, postgraphie, even has a dedicated section on this: https://www.graphile.org/postgraphile/production/
Let me quote: "Due to the nature of GraphQL it's easy to construct a small query that could be very expensive for the server to run".
And lo, and behold, it doesn't really have a solution against it.
So you have to either revert to basically REST with a predefined number of whitelisted queries, or pay for an experimental extension that attempts to calculate the cost of query.
> And if you split fetching the data by multiple endpoints and pretend your job is done, basically delegating the problem to your clients, what else can I say?
You can say something that actually shows that you know what you're talking about. Because you clearly have very little knowledge about REST and very sparse knowledge about GraphQL. You don't even know that unbounded complexity and infinite recursion are inherent in GraphQL.
And I can spell it to you again, you know structure and complexity of your query before you execute it. Feel free to ignore it and disguise ignorance behind I’ve pointed out by reverting that back on me. I’m asking a pretty simple questions, while you’re deflecting with an assumption that I need to prove my worth of your time, lol I rarely engage in online discussions and only if know for sure what I’m saying.
Literally in the example provided by postgraphile. It literally shows how to DDOS a GraphQL service by constructing a simple recursive query. It literally shows how even a few levels of recursion will break your server. It literally shows that by default GraphQL - and postgraphile - has nothing against this. So yes, you can increase recursion in the query ad infinitum, which is my point that you fail to understand.
> Feel free to ignore it and disguise ignorance behind I’ve pointed out by reverting that back on me.
Stop projecting. You can't even understand what the tool you mentioned does, and the problem the tool's own documentation describes.
Adieu.
Firstly, GraphQL does not allow for infinite recursion; it is literally not possible to do infinite recursion in GraphQL; the GraphQL spec even has a section on this: https://spec.graphql.org/draft/#sec-Fragment-spreads-must-no...
Secondly, it's extremely easy to add a GraphQL validation rule that limits the depth of queries; here's an example of one where it takes just a single line of code: https://github.com/stems/graphql-depth-limit . This isn't included by default because there are plenty of solutions you're free to choose between, many of which are open source, depending on your project's needs. For most GraphQL APIs, persisted queries/persisted operations is the tool of choice, and is what Facebook have used internally since before GraphQL was open sourced in 2015. (Unlike what you state, this does not turn your API into a "REST API," it acts as an optimisation on the network layer and once configured is virtually invisible to client and server.)
It's literally impossible to do infinite recursion anywhere because it's physically impossible to write down an infinite recursion.
However, if you look at the very example you provide on that page, you will see what I mean by infinite recursion. Moreover, you link to the Apollo page which literally has this example:
--- start quote ---
This circular relationship allows a bad actor to construct an expensive nested query like so:
--- end quote ---Is 10000 infinite? No. Does it illustrate my point? Yes. Have you missed the point? Also yes.
> Secondly, it's extremely easy to add a GraphQL validation rule that limits the depth of queries
1. This statement is not even remotely true in general sense
2. It is not the default behaviour of any GraphQL implementation (because it's inherent in GraphQL)
3. The "extremely easy" solution for this particular case relies on an external package that needs to be added on top of something else. In your case it's not even added to postgraphile. It's added as an extra middleware to some other graphql library.
And that covers only one dimension: potentially infinite recursion. The other dimension is potentially unbounded complexity. For which the following is true:
1. It's inherent in GraphQL
2. Is not even solved by PostGraphile, except in an experimental paid package
3. The primary mode of mitigating this is disallowing arbitrary queries by providing only a whitelists of allowed queries (so, basically falling back to REST)
So in the end you end up piling more and more complexity on top of other complexities to arrive at a whitelist of allowed queries, ... which is basically just poorly implemented and over-engineered REST (well, REST-ish).
Honestly, no idea why you're fighting the facts of life that you yourself even document on your own product's pages.
I know I’m arrogant, but yours is off the charts. Thanks for confidence boost!
REST: you know exact queries that frontend uses, and can optimize accordingly
GraphQL: users can and will construct ad-hoc queries of any complexity, so they can and will hit unoptimised paths
lyxsus on HN: GraphQL gives you more control than REST.
and at the same time
> This gives you the flexibility of GraphQL
The flexibility of GraphQL is in the arbitrary queries.
> lyxsus on HN: GraphQL gives you more control than REST. I like that :)
So what you are saying is it's better to leave this complexity for the frontend developer to handle on the client side? Very wise!
And yes, GraphQL makes backend significantly more complex, fragile, and prone to significant performance issues.
You have much more flexibility to solve problems on the back-end. On the front-end, you are fundamentally limited by the fact that you have to transfer all of the data and code to the client-side while the user is waiting.
At least caching can be solved somewhat, but not on the protocol level.
I think GraphQL is great for applications where there are no apparent caching or concurrency options.
But even things like partial mutations are fuzzy. The auth packages for it are immature, the integrations with channels is immature.
We provide legacy REST api's for some of our clients, but we are using Graphql internally.
Coupled with Hasura (https://hasura.io/) you have an extremely flexible, safe, and automated api that can consume multiple data sources and integrates very cleanly with serverless architectures.
A lot of the comments in this thread read like pure FUD, and I would encourage those of you on the fence to do your own research and evaluation before listening to the crotchety old devs (disclaimer: I am a crotchety old dev) here who are afraid their REST chops are obsolete.
That coupled with GQL automation and type generation has literally taken months off of the development cycle for the last two products I've built. That has a real $ value that has led to actual success for those products. Not to mention that these API's are extremely flexible for the end user in a way that comparable REST api's could only dream.
We have a pretty robust unified graphql api that handles millions of requests per second. Its has recently replaced siloed REST api's and now provides a common interface and RBAC for all of our data, which is housed in 5 different DB engines.
Previously most of the data was in MongoDB, so implementing GQL allowed up to regression test the api surface while migrating the underlying data. Remote schemas and persistent queries were pretty integral to that effort.
[0]https://www.youtube.com/watch?v=Wtrsedkrmn4
I am a happy customer and am in the process of converting the rest of my organization. It scales up really well and is one of the few pieces of tech I have used in the last few years that wholeheartedly recommend.
On my current project, we're using Graphana with Postgresql on the server and Apollo on the client. You create a new table in database, click a couple of buttons in Graphana admin panel, and the client now can query those tables, without a single line of code on the server! This part is awesome.
What is much less awesome though, is when you have a normalized database, and entities with many layers of links, and your client can generate GraphQL queries with so many crazy joins that will take your production database 30 seconds to complete — all while accessing public data, with no authentication required. So far, I haven't seen anybody figuring it out to DDoS our server, and every time this happens with real production queries, I get a fun index writing task.
However, just being able to run into database perfomance limitations by writing code on the client seems wrong. There's always going to be weird joins that we won't optimise for, and sooner or later there will be determined DDoSers who will figure it out and will be able to spam our server much more effectively with each query. I'm not yet sure what's the right way to alleviate this problem is, it's just strange that no one is talking about it.
Edit: I think I have been proved wrong by lukeramsden's comment below; or at least I should research this more before having an opinion on this matter.
[0] https://www.graphile.org/postgraphile/production/#denial-of-...
I see people use GraphQL as the new ORM. I see it used by people who don't have that much experience with databases. I see it used by people who have nothing much to do. It is sometimes about cost requirements. You can just spin up one of those automatic graphql servers that creates the entire backend for you. Sure it doesn't have any logic or security or performance, but it was quick to get up and going and the client is not experienced enough to notice in the beginning. It is often used with Apollo client, so these inexperienced developers then have all kinds of caching issues due to the automatic caching the client does that they don't really understand.
I see it having an application at FAANG scale, where there are teams of front end and back end people, and front-end people can just create the UI without talking to the back-end people. I see it being used at places with enough scale to have multiple graph databases, not SQL databases, or multiple types of databases that need to be unified.
That isn't where it is used in most cases though. It ends up being a very limited version of SQL that is slow. I think it would be good for maybe a public API.
If you are one small to medium sized team. Or honestly even 2 small to medium sized teams, GraphQL is overkill. The people working on the API for your frontend are either right next to you, or even you yourself. So there’s no need to introduce this big backend framework with a strict API. There’s just little to no process or code quality benefit for small teams. Unless someone on your team is absolutely terrible, and that terrible person is going to cause problems anyway.
GraphQL is touted as a technology which saves developer time by avoiding the need to develop REST APIs, and instead just expose your database to the world and let your frontend just get whatever data it needs.
No wonder you're seeing small teams using it. It's not because of FANG, not because of cargo cult development, not because of incompetente. It's because small front-end teams don't spend their scarce resources on areas where return of investment is limited.
Where are you seeing this? There are a couple of solutions that follow this model (e.g. Hasura, Postgraphile), but it's not an approach recommended by any of the creators of GraphQL, or the bulk of its users.
Why, for starters right on GraphQL's own slogan? In the fact that GraphQL is sold as the API layer for front-end applications?
"Faster frontend development"?
"Iterate quickly on apps without waiting for new backend endpoints"?
These are direct quotes from GraphQL's front page.
You need to be completely disconnected from the topic to not be aware of GraphQL and it's value proposition.
This is the part I was focusing on, sorry if there was confusion. For context, I've been working with GraphQL since June 2015, so I'm pretty intimate with the topic.
It's worth noting that those slogans you quoted are from graphql.com rather than graphql.org. The latter is the official site, the former (.com) is owned by Apollo and isn't official in any capacity -- something I personally find to be an extremely questionable situation. GraphQL's actual slogan is "A query language for your API".
My opinion here is somewhat unusual -- even with the GraphQL world, but I think you can get benefits from using it even at teams of just 1 engineer. But you _definitely_ don't need to be anywhere close to FAANG scale for it to be worth the investment.
People who know how to use GraphQL aren't likely to be dissuaded from using it well by a blog post or some internet comments, so this is an argument in favour of telling people “if you have to ask, GraphQL isn't the right tool for the job”.
I think GraphQL actually _is_ the right tool for many of the jobs people are using it for (API layer for 1st party clients), but they're often using it poorly due to many of these tools having slick APIs that let you be productive alarmingly quickly -- you only feel the pain much later.
GQL works well when you have unstructured data that 'links' to other or in places where you need to query data in various different ways, with different joins that REST doesn't help (or you end up creating a querying language on top of your REST endpoints anyway (/clients/?age>2&link=business,jobs&business.broke=false&etc etc etc)
Then you need to do this for pretty much every REST endpoint that may need this functionality. With GraphQL the server knows how to fetch the individual entities along with the filters, and create a nice graph of it for you (and you can optimize the resolvers if you dont want to have a lot of DB calls).
Saying people are using GraphQL as the new ORM is the same as I saying people are using Ruby on Rails (and their scaffolding) as the new low-code solution.
That said it's good to see a counterpoint to the GraphQL push. With gql, gRPC, etc, it's a great time to be working with APIs.
GraphQL absolutely has it's place, as others have eloquently described here, but it shouldn't be the default choice for small teams "just because".
Some of the comments about performance and security are obviously from people who haven’t taken the time to do a proper deep dive. I’m sure there were similar arguments against REST from the SOAP crowd.
GraphQL is not that different from REST.
"(...) The infamous 6 connections per host limit does not apply to WebSockets. Instead a far bigger limit holds (255 in Chrome and 200 in Firefox). (...)".
We do single connection per session (tab/window), there's no need to have more.
It's a spec and not a architectural approach, which makes all GraphQL APIs more uniform than all REST APIs.
It comes with a type-system that makes code generation really easy and allows for tools like Graphiql, which are orders of magnitude better than what most REST docs deliver.
Can this be done with REST?
Sure, just use something like OpenAPI.
Problem is, most REST APIs don't use such tools/specs, but most GraphQL APIs do.
Github’s graphiql explorer was a joy to use and has saved me hours. For fetching a graph of nested data, graphql absolutely shines giving you fast responses of only the data you need.
For mutations though, graphql is a giant pain in the ass. We wrote a bunch of things using graphql mutations and after two months reverted all mutation code back to using REST api. GitHub was flakey, some things didn’t have error responses. Mutations would screw up encoding “ character and it was just painful.
REST api was much more deterministic and easier to work with. POST/PATCH/PUT/DELETE map well.
I wish graphql didn’t invent its own quirky language and stuck to good ol json.
In my experience graphql wasn’t worth the hype. There is a lot of over complication. We’ve got a lot more production success sticking to the basics.
NOTE: we were interfacing with github’s graphql api from python. Outside of js, graphql tooling is sparse and sometimes non-existent.
That just seems like API problem rather than GraphQL problem. The equivalent would be REST API that just returns 500 without any additional info. You can be lazy in both stacks, I don't think any one of them particularly prevents you from being lazy about handling errors / typing useful error messages.
> Mutations would screw up encoding “ character and it was just painful.
Interesting, haven't heard about this. Also cant come up with how this is related to GraphQL, as you are just transferring string, just like you would do with REST. It seems more of an problem with some proxy/grapql framework layer that didn't handle the character correctly?
> REST api was much more deterministic and easier to work with. POST/PATCH/PUT/DELETE map well.
I don't see this as a big win, in GraphQL you just have `somethindUpdate` `somethingCreate` `somethingDelete` mutations, it is true that it is up to you to keep the naming consistent but nothing really that would be big trouble, or win for the REST.
> I wish graphql didn’t invent its own quirky language and stuck to good ol json.
If they did that you would end up with some quirky JSON query and schema syntax that would look like json schema or the mongo query schema. It is true that if you do new syntax you lose some json tooling that could be used (eg syntax highlight) but I don't see that much stuff transferable to the problems that GraphQL is solving.. so you would still end up with bunch of custom tooling on top, and when you need that you might as well go the way they did, with new syntax, that is not as quirky as whatever mongo/json schema like thing they would come up with.
> There is a lot of over complication.
This is definitely true and one of the most overlooked things by GraphQL evangelists, the "additional complexity layers" are non negligible.
In the vast majority of cases, you don't need to build mutation inputs (or anything else, really) in GraphQL syntax. Python requests library should be more than enough if GraphQL is being used the right way.