Why not use GraphQL?
wundergraph.com
wundergraph.com
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:
let results = await fetch('/rest/Users/?fields=' + JSON.stringify(
{
id: true,
first_name: true,
groups: {
name: true,
permissions: {
name: true
}
}
});
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].
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.
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.
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.
- Auto-generated, type safe entities from source to client, including relationships = fewer bugs
- Ability to unify different backends (eg a database, warehouse, external APIs, cloud storage)
- The “application data graph” concept always brings huge clarity to the architecture design - you get to build your mental model in code
- GraphiQL is excellent
Having said this, most of the benefits come from the incredible tooling, eg for our stack Graphene, Graphene-X bridges, Typescript, Apollo. I would never consider writing a GraphQL server from scratch, and we’ve had bad experiences with instant database -> GraphQL solutions (not really keen on writing my application logic in SQL). It’s also not an either or - our current app uses REST for file uploads and stream large datasets to the client. And ofc, you can achieve many of these benefits with other solutions.
Wundergraph looks like a great addition to the ecosystem, it would already remove boilerplate from our app.
One of the reasons it fell out of use is XML is verbose and typesafety is not cool anymore.
This is rapidly reversing as the javascript ecosystem has increasingly adopted typescript in the last two years. I, for one, refuse to start a new front end without it, and the only other js dev I've spoken with recently who disagreed had never actually used typescript and didn't want to "write a bunch of interfaces like java".
I would not say fell out of use, most enterprise-grade apis, old or new, will have one -- think bank/government/big corp. GraphQL is not there yet - as other commenters pointed out the tooling is not good enough outside JS world, security is complicated on the service side, and the protocol is just to young - the official release is two years ago, so it may start appearing just around now.
For type safety, many backend frameworks generate OpenAPI specs automatically, and you can generate Typescript stubs based on this. Ditto for gRPC and gRPC web. We use these.
But I’ve not seen a replacement for the “application data graph” (but would be interested to learn about them!). The link from @jefflombardjr [0] explains it nicely - it is a great abstraction (in certain situations). Modelling your application data graph is like modelling a good database schema - when you get it right, the rest of the application follows naturally. It’s magical when it works, and I’d happily do it even if it’s just me working on the project.
And GraphQL has a great ecosystem, that is the advantage over niche tools. Example - last week we added auto-generated GraphQL types and relationships for Postgres JSON fields, with the help of [1]. No more malformed JSON breaking our app.
Note this is all in the context of a web app. Reading other comments, the tooling seems to be less developed on other platforms. And again, without decent tooling (especially for the server) I wouldn’t touch it.
[0] https://medium.com/@JeffLombardJr/when-and-why-to-use-graphq...
Are you saying that your client (interface) has a direct relationship to your database schema...?
> (not really keen on writing my application logic in SQL) Maybe you should learn it, as it's really simple and powerful as opposed to the GraphQL language. But for the record, neither do I write SQL queries using my generator and last time I had to write SQL was in the 2000s when I was still using PHP. Nowadays I just write my data models and generate the backend and implement the frontend. And I don't need GraphQL for it. @ngrx-data for Angular simplifies communication with the backend. And since I generate my notifier/updater too I have real-time updates via websocket. There's nothing GraphQL offers I don't already do since 2016.
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 developer.".
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:
query maliciousQuery {
thread(id: "some-id") {
messages(first: 99999) {
thread {
messages(first: 99999) {
thread {
messages(first: 99999) {
thread {
# ...repeat times 10000...
}
}
}
}
}
}
}
}
--- 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.
With REST, all my APIs are defined and I can easily test all the database queries my server will run, check that they're indexed, etc. But with GraphQL, my understanding is a client might be able to request something like "Give me all users whose phone number starts with 555". It's possible that query isn't indexed, and after deploying the app we end up tanking our database performance, right? That seems like a huge potential issue to me, but I might be misunderstanding how it works in practice.
But that's not using GraphQL "the right way", is it?
I mean, GraphQL's value proposition is quite literally letting front-end developers run all sorts of ad-hoc queries without having to bother about indexes, and only care about the data you wish to extract.
If all you want is to run fixed queries then you're already better off putting up a REST API.
As others have stated persistent queries are the answer. You can disable them in local dev if you want to give your devs more flexibility, but I have found it usually isn't necessary.
Zero difference from your REST call.
To me the acid test, since getting burnt by both XML-RPC and SOAP has always been “can I drop a standard HTTP proxy Like nginx between this thing the layer behind or in front to cache reads?”
GraphQL _seems_ like you can’t really do that so you end up having to build caching into your app, which in turn - in my experience - always leads to systems you can’t predictably reason about
There's no magic there, it's left up to you whether you expose such functionality and you are in full control of all fields that make up your API. Most of the time your APIs will reflect your database associations `{ users { posts { comments } } }` which should be indexed anyway. Custom queries on top of that, like a search filter, can be indexed/optimized individually. Resources can be paginated quite easily and you can also enforce a maximum depth when requesting associations, so that you don't end up with requests too large to deliver.
The main problem with GraphQL comes from the many different ways you can use it, which makes caching or eager loading difficult.
There's also libraries (usually in-house) that let you query for every relation off that specific table. You can imagine how it works just match up the fks and expose in the graphql schema. That gives you control of what not to expose as well.
I think backend devs should be more worried about loosing 75% of their work when it comes to Hasura.
That's not exposing database associations. At most that's exposing aspects of the domain model which are also reflected in the persistence model.
The example `{ users { posts { comments } } }` reflects that in the abstract modeling of a message board, this relationship exists. The representation of this relationship will change depending on the database implementation; a document db may store the data explicitly in the hierarchical form, while a relational db would store them with a series of joins.
As best I can tell from my limited experience, GraphQL is just exposing the bones of your relational schema without giving it much domain behavior. It's the software equivalent of offering a grocery store full of ingredients when all the hungry person wants is a sandwich.
There is just a lot of anti-patterns floating around because of tightly coupled API / DB's.
People apply this same logic to GQL and get confused.
And programmers will apply this same anti-pattern to GQL, so it doesn't really solve that problem, and arguably makes it worse for the reasons stated in the un-indexed field example.
Part of the benefit of gql that people often overlook is its self documenting nature and when tied with automation tools its ability to provide a lot of flexibility for developers without compromising you db.
The gql server is ultimately what is responsible for this, and we use schema introspection to ensure the searchable / sortable fields are only exposed if indexed.
With GraphQL, I'm asking about how clients _could_ write arbitrary requests, that since the backend doesn't know about them ahead of time, can't optimize for with indexes.
This is just extremely embarrassing to say. 1990s John Perry Barlow esque fantasy.
It will do no such thing and nothing ever will.
GraphQL completely unfit for purpose for any purpose. It's not even a Query Language. It's as much a query language as JSON. You have to build almost everything yourself. At least REST uses the standard HTTP status codes for stuff, in GraphQL you have to roll your own for EVERYTHING. And thus EVERY COMPANY WILL DO IT DIFFERENTLY even more than REST Apis are different because there is no expectation to conform to anything. Most resolver libraries are also completely naive.
It's like facebook was just intentionally trolling.
Here's an idea for pet project: an interface for NoSQL databases where the input is a jq filter command and the output is JSON.
jqml? GraphJQ? It's up to you.
The backend seems like a black hole of information in the GraphQL content that gets pushed to news aggregators.
On the other extreme of the spectrum, you allow the client to query the data with much freedom. This means that you have more of a generic resolver which maps GraphQL queries into an ORM or something else that generates your DB queries.
In this mode, you have challenges regarding speed and optimisations. At a previous assignment we for example hand crafted the resolution of some especially nasty queries to increase performance, and left most for some ORM to figure out. We kept the database index structure up to date to match queries we saw from the frontend using metrics tools.
Another thing is security. If you use this model, you are basically allowing the client to query around your graph of data in whatever way they want. This means you need to have some way to answer the question "Should User 37 be able to read field X on Object Y with ID 42", and implement that in your resolver. This is quite tricky, compared to REST or static graph QL queries where you just decide which objects / fields should be returned.
(There is also some interesting DoS attack scenarios when going this route, where a malicious query can just explode in complexity, so you'll have to make sure to solve that some way as well...)
Tooling back then was probably much more primitive than it is today, so apply that discount to the subsequent statements.
Writing GraphQL resolvers for the API that we were building was painful and required a solid understanding of our data model and what the database was capable of (we were using MongoDB). We were much happier at the time to stick to tried and true REST API tools and frameworks than to jump on the GraphQL bandwagon.
All the complexity of managing REST calls was simply pushed from the client side to the GraphQL resolution server. This complexity seems irreducible to me, and I am highly skeptical of anyone claiming that they can make this complexity vanish.
Have never so much as been tempted to use GraphQL since then. Unfortunately, this probably also marks my entry into dinosaur-hood.
That itself is useful. It is much easier to manage complexity on a server that you control in the same datacenter as your DB in a language of your choice than it is in JS with limited bandwidth.
There are likely specific use cases where GraphQL > REST but the barrier to entry is so much higher that I think you'll continue to see the interest wane[1] unless something dramatic changes
[1](https://trends.google.com/trends/explore?date=today%205-y&ge...)
When their GraphQL API was released its data structures were similar but not identical to the REST API and some very important fields and features were missing which translated to a "90%" adoption by developers who needed those missing pieces. Additionally (and somewhat in keeping with points in the article,) they also introduced API versioning at this time which added a good amount of friction within the community.
More generally the issue with Shopify's GraphQL APIs is its lacking features (eg, list totals, offset pagination, object fields) which are (or had been) particularly important to the ecommerce domain and they've struggled to provide any meaningful alternatives.
As an example, developers working with ecommerce applications often have to process data en masse (fulfillments, inventory, etc..) and with the Shopify REST API and it's offset pagination these tasks were trivial to parallelise by simply chunking the workload based on the pagination method. In the GraphQL API offset pagination was removed in favour of cursor pagination which has no reasonable alternative to parallelise tasks in the same way, this requires developers to rewrite core logic and services for what may have previously been a very acceptable, efficient and most importantly working application.
The issue with Shopify's GraphQL API is not GraphQL itself, but rather the implementation of the API not meeting the requirements of the consumer - and the fact that those consumers were forced to switch to a different API without feature or even conceptual parity didn't promote feelings of joy or glee about the situation.
Personally I think their push for GraphQL was due to internal operational issues and their need for a more efficient system. This has been seen in their reasoning for reducing the timeout of an API used to fetch shipping options (from 10 seconds to 5 seconds) in preparation for Black Friday / Cyber Monday sales events, their announcement provided some developers less than a single business day to respond to the changes[1] which were dropped after community backlash and then changed to address the feedback.
[1] https://community.shopify.com/c/Shopify-APIs-SDKs/Changes-to...
Perhaps the benefit is what ryanar writes here [1], that it exposes a useable db-admin UI to front-end teams. It seemed to me this could have been achieved with something based on REST but maybe I'm just not thinking it through.
Now that I think more, it wouldn't really be sufficient to produce SQL for a front end team because you don't want them to be able to create inefficient queries.
I guess my main gripe was that GraphQL uses POST requests and nobody told me how this makes cdn caching harder so I started hating on GraphQL :-/
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.
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.
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.
"(...) 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.
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.
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.
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-...
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".
But even things like partial mutations are fuzzy. The auth packages for it are immature, the integrations with channels is immature.
However, REST is so much easier to build and query. Normal APIs use GET requests which are easy to cache in a cdn. GraphQL uses POST by default and to cache that you need to convert the request somewhere, either in the cdn or your web server.
At the end I realized I was just messing with it for a small project to learn it. It really isn't worth it IMO. The problems it claims to solve can be solved with REST provided you understand the issues.
I've found that this leads to a huge miss on the observability side. The ecosystem of tools doesn't solve for this well today, especially when it comes to the various vendor integrations.
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".
I don't need any specialized tools or secret sauces to build a REST server. I already know SQL and when my frontend needs something from the database, I simply write a query with that or do a fetch with my ORM, crafted specifically for that endpoint. Couldn't be simpler.
GraphQL is a solution for building APIs when you aren't involved with the frontend at all. Even then the time invested learning, the extra layers of complexity, "magic" and tooling hardly make it worth the effort.
I don't build APIs that way though. All of my APIs are purpose-built specifically for a given frontend and if I'm not creating both the frontend and the backend, then I'm closely collaborating with someone who is.
Keep it stupid simple. This is the way.
> Users expect an experience as native as it could be from websites. The Jamstack is taking over on the frontend. Hybrid models with server side rendering and dynamic Javascript clients are the enablers of these applications. RESTful APIs excel at a different set of problems. They will not go away, quite the opposite! They’re just not the right tool for this style of applications the industry is currently shifting towards.
...and REST or RPC for anything else.
> I think REST APIs are a perfect tool for internal APIs, partner APIs and server to server communication. This is an area where GraphQL doesn’t really bring any benefits over REST. Alongside RPC it will have a great future in this area. GraphQL on the other hand is more than happy to wrap resource- and RPC-based APIs.
(Side note: does anybody know why Apollo recommends using the websocket driver for subscriptions only?)
It is very easy to provide additional graphql schemas that expose business logic as a remote schema.
For me 3 reasons "why not GraphQL" are: 1) Access control: rights, permissions, roles - they are just a fog when client can write own query to DB.
2) Knowledge sharing: when your client knows too much about DB, you have a very tight coupling.
3) Complexity of the service layer. If there is no tool for the language you love - write your own GraphQL library. And there is no guarantee that your other client will be able to reuse this API.
GraphQL does not have the same level of complexity as Docker; nor is it as obscure. With the libraries like apollo; especially if you have a "component driven" approach; being able to craft components as truly self-contained modules is quite freeing.
Could you do this with REST? Probably. However with GraphQL managing the complexity of it is easier. This type of an argument could also be made for SOAP; since you could probably implement something like this there too. With GraphQL somebody already did that for me though; so I can just use it. I don't have to worry about creating multiple endpoints for my use cases; I only need to worry about specific entities and how to fetch them. I no longer need to worry about whether or not I am batching my queries etc because it is managed for me.
This allows me to have (to the greatest extent) plug-and-play components that I can just chuck into places.
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.
It is so seductive to imagine that "opening up the back end" is the answer. But, as many here have pointed out, unfettered access to the data model and transactions leads (yes) inevitably to the kinds of ad-hoc interactions which no back-end can rapidly adapt to. Kind of.
It doesn't rapdily adapt mainly because the server team doesn't want to be dominated in the organization by the whims of Marketing and the client team. This leads client team to demand fuller access, because it is tired of its creativity and velocity getting dragged down by the slow roll of the server team. Throw in an occasional economic downturn with pressure from management to rein in back-end costs and this becomes a drama truly worthy of popcorn-munching.
function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default Page
Docs: https://nextjs.org/docs/basic-features/data-fetching#getserv...I have a hard time imagining this kind of architecture scaling well to Real Production Applications, but for whipping something together it does seem incredibly easy.
It’s useful if you need to call an API from the client in a Next.js application but modify the data first, or call multiple endpoints without introducing a waterfall to the client. What you described can be used in a similar way for filtering and processing etc, but only for the initial page load.
This is completely fine and understandable given the use-cases that motivated it, and the community that's been driving it.
But it's not a hammer for all nails. Reading the OP post, it's obvious they have a very narrow perspective when the one thing they compare it to is "REST".
The nice thing with HTTP/JSON, and IMO a major factor in it's ubiquity, is that it's an OK (while not always ideal) solution to implement towards for pretty much any use-case. Performant and stable HTTP clients and JSON parsers/formatters are even part of a lot of standard libraries, and straight-forward to implement should you need to. The benefits of GraphQL compromise this.
protobufs in general and grpc specifically are a much better solution for many scenarios, due to some trade-offs being different. A lot of the issues and concerns brought up by other commenters here is "leaky abstractions are gonna leak". I'm sorry, but there's no free lunch.
IMO it's a bit delusional to claim with certainty that "There will be a future where you can query any system in the world using GraphQL". I'm not even sure I want o live in that future if it means 1) I have to support it and 2) it comes at cost of other protocols.
Is there anything already which lets you deserialise in your view but allows the original body to be forwarded or aggregated. Of course we could pass around all original strings/payloads but that would be complex and error prone.
It is quite hard to define REST interfaces in a way that is optimal for all clients, unless you want the client to do a bunch of extra work (n+1 queries or other type of aggregation).
The author mentions the BFF pattern which could work quite well along with REST, but has not worked out for us in large teams. We ended up with BFFs specific to each client type which all do the same things in slightly different ways and it was hard to share code and do things consistently.
With GraphQL, all the previous BFF logic was centralized in one place but each client could still fetch data in different shapes.
- It has a well-defined pattern/structure so you don't have to waste a bunch of time thinking/arguing about what your REST endpoints look like.
- It lends itself very nicely to automatic code generation for both frontend and backend, so you can define your API first and then build outward from there. This makes full-stack development a breeze.
If you're working on a solo project and you're not sure if GraphQL is right for you, I would say definitely give it a shot. As with anything it takes a bit to really figure it out in your brain, but once you do, you wont regret it or ever want to look back.
Sure, these same restrictions are what can lead to the necessity of versioned APIs, but on their own, they make the API in general a little easier to reason about, and test, at least in some ways.
[1]: Which is not to say that I prefer them nor I think them better overall. Much like TFA says, I think both approaches, and others, have their uses.
I've yet to find something that handles caching, updating of cached objects in such a easy way for OpenApi, it should be possible considering that a well documented schema contain the necessary information, but I haven't seen it.
How well you do it, is.. up to you. Languages and making them are extremely powerful tools, ehm, if you master them. And in any case, one can abuse any thing, by lazyness or by misunderstanding, and grind it into snailing or halt. Anything.
Here, defining and implementing something like graphcool exposing interesting part of (django) query-ORM into a simple language, took about 3-4k lines server side, +under 1k client-side, mostly utility stuff. Except graphene/graphql/django on python on server, nothing else is needed. Zero libraries in client. And now one can talk in that "language" in client, not worry about what server thinks of it, and/or switch the server into another platform/language any time - the contract is defined..
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.
There are caching issues, and you need decent metrics and tracing across your entire platform to have any idea what's going on.
https://grpc.io/blog/state-of-grpc-web/ is from early 2019
How would you handle schema changes in GraphQL? How to you administer who queries what?
Bullshit. I've built a lot of REST APIs and every time mobile apps were reusing API without any issues.
I feel like whomever wrote the syntax of GraphQL was just concerned with getting it working with the least effort possible.
(non-zero that person(s) is right here and reading this. I'm sure you're smarter than I am and I just haven't fully immersed myself into this world yet. It's happened before.)
SQL would have been such a better choice. It’s been battle tested for decades and is so much more expressive.
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
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?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)
NB: I can't authenticate the veracity of the comments
At some point, it is better to leave the custom solution field and go for graphQL before rebuilding it.
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.
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.
In the end, the question that proponents of a new technology in a team usually avoid addressing is: "what specific problem we have here and now that this new method solves, and why can't this specific problem can't be solved by the simple addition of X to our current solution, without the need to change absolutely everything?" Because even if a new library solves a laundry list of issues, usually the ones that need to be solved in a specific context- the bottlenecks- are just one or two. And those usually can be solved by small incremental changes.
GraphQL is bad. You increase transparency on the client side and decrease maintainability on the server side. It's the worst of both worlds. I don't understand how people are advocating it, but then again you know how it goes, "eat more shit, millions of flies can't be wrong"
Plus now you have to learn yet another query language.
Trying to project complex queries into a list of flat strings (path) is just not good. Having a standardized query language is much better.
> How is writing queries in the front end and exposing those queries a good idea
It's better than making x technical requests for one semantic requests because it's easier to keep track of what is requested and what is just correlated by time.
> How is exposing the back end data structures a good idea?
If you do that with either REST or GraphQL you are either doing it wrong or you care about speed a lot and generate your graphQL from your backend structures.
GraphQL is especially nice if you have one backend and one or two frontends that you control.