After 6 years, I'm over GraphQL(bessey.dev) |
After 6 years, I'm over GraphQL(bessey.dev) |
[0] https://blogs.windows.com/msedgedev/2024/05/28/an-even-faste...
Has anyone experienced something similar with typedb? It feels a little too good to be true. Make it seems like graphql and nosql trauma.
https://blog.tailcall.run/writing-a-graphql-backend-by-hand-...
GraphQL makes sense only at a certain scale when you have multiple APIs built by multiple teams that need to be exposed as a single endpoint. GraphQL as an API or APIs is the perfect use case and the one that it was designed for.
In every other case, REST is harder to do wrong and easier to do right. The tooling for it is widely supported and well known. Every aspect of building an easy to use, easy to own, easy to scale API is -- well -- just easier with REST.
I have seen more than a few small, 4-8 person engineering teams reach for GraphQL and then wonder why every cycle starts feeling slow. In a 4-8 person team, the devs are usually working full stack and if not, then they are working closely enough that having a highly flexible API layer servicing the front-end doesn't make any sense since it's either the same devs or they're one Slack ping away from getting the right shape from the backend in one simple `GET`.
Like the author, I've found that the story with OpenAPI nowadays is really good. I have a short writeup here with .NET that shows hot re-generation of the API into a TypeScript definition that can be used with React, Vue, or your framework of choice: https://chrlschn.dev/blog/2023/10/end-to-end-type-safety-wit...
This workflow is super productive and perfect for small teams working full stack; far easier than getting GQL right.
GraphQL makes it easier for front-end developers to do the wrong thing, which is why they love it.
In short GraphQL is optimized for keeping as much functionality working as possible no matter how much instability there is in the backend.
This is a common problem in REST endpoints that consume data from multiple services as well. But the request usually fails completely. On the other hand REST request don't usually touch as many services as a GraphQL request.
it's similar to OpenAPI, but its simpler, and cleaner. In fact, you can generate webrpc schema's to OpenAPI and then generate OpenAPI clients.
Not just for the content but I love it when someone changes their mind (very very hard thing to do) and details out what led them to change.
Frontend - React
Backend - GraphQL
What's extra creepy is the private equity firms squeezing this space dry
Why? Isn't YAML human readable?
I tend to prefer just writing the yaml, but I can also see why these kinds of tools crop up to mitigate the need to remember all the details.
GraphQL can be very powerful, but also very dangerous.
For example the whole n+1 data fetching topic: Yes this issue exists and like the author is mentioning: GraphQL has a well understood and common solution for this problem. On the other hand: In REST world you can have exactly the same issue, but either create a custom solution for this issue or push the issue to the client side, where this issue needs to be solved, too. I could not exactly follow the explanation of the special case of the n+1 problem in context of authorization. "This is actually trickier [...], because authorisation code is not alway run in a GraphQL context." OK authorisation code is not run in a GraphQL context, but why is this then a GraphQL issue?
On the rate limiting issue I also do not see why these issue would by design just exist in GraphQL world: Yes you can have recursive data structures and write queries which can take a lot a processing time to resolve. But again: Why would the same recursive data structure not be possible to be modeled for a rest api and why would the same data not be queriable from a rest api? My guess again is: You _can_ model the same data structure and also _can_ query the same amount of data. And also again: In case of the rest api the complexity of querying this data is just pushed to the client side and that is why it seems easier to rate limit individual rest endpoints. But actually I see no reason why a GraphQL API could not rate limit e.g. on data loader or any expensive operation level, too.
Generally regarding malicious (e.g. malformed) queries: I think this is definitely a valid issue, which should be addressed in GraphQL APIs. I think there should be a common way for application developers to sign their queries somehow and query engines should only attempt to process signed queries. This way only trusted developers are able to write arbitrary queries.
On the "Authorisation" section I can not quite follow the reasoning. Aside from implementation-specific extra-calls to a presumed authorisation framework: Why would domain requirements be different when they are implemented either as REST API or as a GraphQL API?
"Compare this to the REST world where [...] you would authorise every endpoint". OK if you can implement an authorization requirement simply on a REST endpoint, why could you not implement this simply on a Query-Type field in an equivalent GraphQL API? If this is about authorization on nested data structures: Can you not have equally nested data structures on REST endpoints, too? I think in these cases authorization on REST endpoints wouldn't be sufficient, too. Assuming you would avoid nested data structures: Would this not simply push the n+1 problem from the server side to the client side?
My general feeling about the REST vs GraphQL debate is both worlds can in principal cause pretty much the same issues. Even for client side caching I see no real design issue which prevents GraphQL queries and responses to be cached, but probably more like a middleware issue. On the other hand I still see a lot of benefit in using GraphQL: Especially the query flexibility for developers, the solved the n+1 query problem (which may still exists on the rest client side or is solved by a custom solution) and the error handling. I still hate to define exact use of HTTP status codes and custom error payload structure in every context where REST is a new or badly defined concept again and again.
I'm looking at Shopify API at the moment, and there's a notification that they're deprecating their REST API and moving it all to GraphQL. I hope it's a joke. But I suspect not. Enshittification intensifies
In other news, bitcoin will never replace cash, most companies don't need k8s and AGI isn't 2 years away.
(Well... slightly different. It's the FB stamp, not the G stamp)
I worked with k8s and realised pretty quickly it was pointless for my org.
I think it's worth mentioning that there is a GraphQL project which has worked to address every single point elucidated here. Of course whether the framework's conventions satisfy your tastes and sensibilities is an entirely different story. The project had at least an answer if not the answer to every gripe listed in this article by the end of 2022.
Despite having basically solved all these issues two years ago, there's been a consistent stream of articles, videos, and podcasts like this one claiming that GraphQL is too complex and the GraphQL ecosystem doesn't provide any tooling or support for managing these complexities.
The great irony is that the framework in question is now pivoting away from GraphQL. Seemingly no one wanted to use a GraphQL framework. But why? Whenever someone learned about the framework, they would say to themselves:
"Well I don't want to use a GraphQL framework since GraphQL has all these problems like auth and caching and rate limiting and performance. It's just too complex so I'll avoid any frameworks that use GraphQL." They would never seem to realize that the very framework they were refusing to use was literally the answer to the justification provided for why they didn't want to use the framework. Eventually, after having this exact conversation a few hundred times with a few hundred devs, I decided that there's only two ways I could explain what was happening, either:
(1) Every time while trying to explain this, all of these developers were experiencing some kind of out of body dissociation not dissimilar to a stroke or brain aneurysm which made it impossible for any semantic meaning to reach them.
(2) These developers just didn't like GraphQL and didn't want to use GraphQL. They were making up a bunch of reasons to not use GraphQL but they had no interest in a framework which solved these issues cause the issues weren't the problem, GraphQL itself was the problem.
Since I've already spent hundreds or even thousands of hours trying to explain to the open source web dev community how RedwoodJS solves these issues, you'll have to forgive my laziness today and make due with this ChatGPT rebuttal instead of another one of mine.
Understanding RedwoodJS in the Context of GraphQL Criticisms: A Detailed Response
The blog post raises several valid concerns about GraphQL's use in production environments, particularly around security, performance, and complexity. Here's how RedwoodJS addresses these issues, considering the specifics mentioned in the blog post.
1. Attack Surface - The blog highlights that exposing a query language like GraphQL increases the attack surface of an application, necessitating robust security measures. RedwoodJS leverages GraphQL Armor, which provides built-in protections against common GraphQL vulnerabilities. These include rate limiting, depth limiting, and cost analysis to prevent overly complex queries. Additionally, RedwoodJS uses Envelop plugins for enhanced security measures, such as blocking field suggestions and masking errors, which are essential to prevent information leakage and mitigate potential attacks.
2. Authorization - GraphQL's flexibility can lead to challenges in properly authorizing access to different fields based on context. RedwoodJS integrates authorization directly into the schema using directives like `requireAuth` and `skipAuth`. This ensures that each query and mutation can enforce authentication and role-based access control efficiently. By embedding these security checks into the GraphQL schema, RedwoodJS helps developers avoid the pitfalls of broken access control.
3. Rate Limiting - The blog points out that GraphQL queries can vary significantly in complexity, making it challenging to implement effective rate limiting. RedwoodJS includes mechanisms to estimate and limit query complexity. It supports configurations to set maximum query depth and complexity, thus preventing queries that could otherwise lead to server overload. These settings help ensure that the GraphQL server can handle incoming requests without being overwhelmed, addressing the concern of unpredictable query costs.
4. Query Parsing - GraphQL's requirement to parse queries before execution can lead to vulnerabilities if not handled correctly. RedwoodJS mitigates this by implementing limits on query size and the number of operations, ensuring that the parsing process does not lead to excessive memory consumption or server crashes. This approach helps safeguard against denial-of-service attacks that exploit query parsing vulnerabilities.
5. Performance - The blog mentions issues like the N+1 problem and challenges with HTTP caching in GraphQL. RedwoodJS uses the Dataloader pattern to batch and cache database requests, effectively mitigating the N+1 problem. By ensuring efficient data fetching mechanisms, RedwoodJS maintains performance even with complex queries. Additionally, while HTTP caching is not inherently compatible with GraphQL, RedwoodJS’s structure and client-server interactions are designed to minimize redundant data fetching.
6. Complexity - GraphQL's flexibility can lead to increased complexity in codebases, making it harder to maintain and debug. RedwoodJS aims to simplify the development process by integrating various tools and abstractions that reduce boilerplate code. The framework's philosophy of convention over configuration helps maintain a clean and manageable codebase. Moreover, the built-in support for Cells (components that handle data fetching, rendering, and updating) abstracts much of the complexity away from developers, allowing them to focus on business logic rather than the intricacies of GraphQL.
7. Conclusion - RedwoodJS addresses many of the concerns raised in the blog post through its robust tooling and thoughtful abstractions. By integrating security measures, optimizing for performance, and simplifying the developer experience, RedwoodJS presents a compelling solution for building modern web applications with GraphQL. While the criticisms of GraphQL are valid, RedwoodJS's approach demonstrates that with the right framework, many of these issues can be effectively mitigated, making GraphQL a viable choice for many projects.
> if you expose a fully self documenting query API to all clients, you better be damn sure that every field is authorised against the current user appropriately to the context in which that field is being fetched.
The same is true for a "regular http API" [now abbreviated as "rest API"] (in case it's not clear: imagine how the http API would look like and think about if it would be somehow magically secure by default. Spoiler: it won't). Security by obscurity was never a great thing. It can help, but it's never sufficient on its own.
> Compare this to the REST world where generally speaking you would authorise every endpoint, a far smaller task.
Just think about how many endpoints you would actually need to cover all combinations that the graphql API offers.
> Rate limiting: With GraphQL we cannot assume that all requests are equally hard on the server. (...)
It's true. However: a rest API only makes that easier because it's less flexible and you have to manually create one endpoint for each of the various graphql API combinations. So instead, a classical graphql mitigation that the author does not mention is to simply require the client (or some clients) to only use fixed (predefined) queries. That is then the same as what a rest API does, problem solved. So graphql is not worse of here, but it can be much better.
> Query parsing
This point is actually fair, except for the claim that there is no equivalent in REST. That is simply not true, as there have been many cases where rest frameworks worked with json and could be ddos'd by using large json numbers.
> Performance: When it comes to performance in GraphQL people often talk about it’s incompatibility with HTTP caching. For me personally, this has not been an issue.
Funny, because that is indeed one factual disadvantage of graphql.
> Data fetching and the N+1 problem: TLDR: if a field resolver hits an external data source such as a DB or HTTP API, and it is nested in a list containing N items, it will do those calls N times.
No, this is wrong. But first: this problem exists in a rest API as well, but worse: instead of N+1 queries to the DB, it will N+1 http requests AND N+1 db requests. But with graphql and some libraries (or some handwritten code) it is comparibly easy to write resolvers that are smart and "gather" all requests on the same query level and then execute them in one go. This is harder to do in a http api because you definitely have to do this by hand (as the auther describes).
> GraphQL discourages breaking changes and provides no tools to deal with them.
What? Comon. In a rest API there is no means to do anything against breaking changes by default. Graphql at least comes with builtin deprecation (but not versioning though).
> Reliance on HTTP response codes turns up everywhere in tooling, so dealing with the fact that 200 can mean everything from everything is Ok through to everything is down can be quite annoying.
True, but that can be adjusted. I did that and made it so that if all queries failed due to a user-error, the request will return 400, otherwise 204 if they partly failed.
> Fetching all your data in one query in the HTTP 2+ age is often not beneficial to response time, in fact it will worsen it if your server is not parallelised
Okay, I'm starting to be snarky now: maybe choose a better language or server then, don't blame it on graphql.
And actually, many real problems of graphql don't even get mentioned. For example: graphql has no builtin map type, which is very annoying. Or, it has union types in the response, but you can't use the same types as inputs due to a lack of tagging-concept.
And so on. My conclusion: the auther is actually fairly inexperienced when it comes to graphql and they probably had a bad experience partly due to using ruby.
My own judgement: graphql is great except for very very specific cases, especially in projects that require huge amounts of servers and have a high level of stability in the API. I would always default to graphql unless the requirements speak against it.
I don’t necessarily disagree but going to play devil’s advocate here on this common foundational viewpoint. Why is this bad? In fact, why not expose the DB directly to the client?
“Additional layers” and “don’t explain DB structure” is security through obscurity. If a DB manages access control directly (field-level or partition-level granularity), any permissible query should run. To prevent pathological queries, add role-based resource quotas and back-off policies.
What about zero day vulns? Well these are going to be a problem regardless of the presence of various infra layers on top of the DB; you’ll have to monitor for data exfiltration to detect these types of attacks in either case.
There’s not a database I’m aware of that handles all of the above considerations, but oftentimes security issues exist in the overlooked gaps that arise between the complex interplay of many dependent systems. If you move the responsibility for security to the DB itself (other than authentication), you’ve removed a lot of the “confusion” that can be exploited, and overall security then depends on just a few factors: 1) correct assignment of DB access permissions, 2) valid external authentication, 3) quality of data exfiltration monitoring.
You might say you’re one simple DB misconfiguration away from disaster, but again, this is already a problem. The benefit of this alternative approach is that you have now shifted the bulk of the security work to one place: very careful rollouts of changes to DB access permissions. You would conduct static analysis to determine the “diff” of how data access has changed and perform sandbox tests. In exchange for this additional work, you can quit worrying about the security of anything downstream of the DB, assuming authentication is set up correctly.
>> If you move the responsibility for security to the DB itself (other than authentication)
And what about all the possible access levels within your auth? Should every DB view have to check a user table to authenticate that the viewer has the priority level to select on it? If it doesn't, all I need to know is the name of a view I'm not supposed to see. What happens if you add a new security level... you change every single view definition? What if your auth + user levels are in a completely different DB in another time zone? Why put that burden on the DB if you get flooded with bad queries from hundreds of clients? That's why I say it's crazy, instead of writing an API endpoint that runs auth first and knows which views or tables are accessible from there and to which users, all in one place. Yes you have slightly more work conforming the client data definitions to whatever is returned from the API, but that seems like a very small price to pay to put all your security and filtering/validation in an easy-to-read middle layer. Of course you should use views and DB perms, but those are not sufficient if someone steals a login or session unless there's a middle layer checking their IP and hash and potential double-taps and lots of other markers that it might be a rogue query before it goes to the database.
"That would be one way to implement the system in a DB-centric way. However we believe that intermediate application code is pretty critical to any GraphQL implementation." [1]
"GraphQL is a client-server dance that needs server-side capabilities, not just CRUD semantics." [2]
Similar concepts of allowing queries and response formats was there in other standards and not new ?
OData is fairly popular in REST world , even older , SOAP XMl had supported with custom query language one robust one I remember T-SQL used in Taleo the old Oracle hiring software
There are many examples of clients doing joins and queries in other standards , it is hardly unique to GraphQL
Maybe I'm missing something obvious, but React isn't mentioned in that post. Maybe you put the wrong URL?
And that's something I would totally agree. Moving from WebUI to native UIs would even be more performant, and if one would care that much about performance (as said in the thread), one would probably not look at WebUI/Electron/Browser at all and prefer native apps.
So that: 1. we enjoy the current tech stack from REST/rpc 2. we gain the ability of quick composition from resolver / dataloader 3. with iteration, we can replace/ refactor endpoint without breaking anything.
for fastapi user, the lib 'pydantic-resolve' can help.
Seems really great to not have each service adhere to another service’s potentially unstable api contract.
Especially if that service is owned by another team.
> Data fetching and the N+1 problem
> [...] if a field resolver hits an external data source such as a DB or HTTP API, and
> it is nested in a list containing N items, it will do those calls N times
Why is this considered a problem regardless of the situation at hand?F.e. using REST, if the nested list contains on average N-2 items that can be efficiently cached, wouldn't that be better than having the cache constantly invalidated on the aggregation of the parent and its items?
Yes there is, simply throw JSON such as `[[[[[[...` at the server. You probably don't have to get into parsing though, nearly all C# (and Node, and Ruby, some Rust even) assumes that memory is, in-fact, infinitely large and just throw network input into a precisely-sized buffer. Just upload a few GB of nonsense to an API endpoint, bonus points if you omit Content-Length.
Another library to check out: Drizzle-ORM
Skill issue.
REST serverless business logic on top and graphql is great
For graphql like needs we use a standard set of props (select, filter, sortBy, limit, offset).
They map to a single sql statement and executed efficiently by PG.
select can be nested properties if we need deeper nesting. Server emits typescript types package for frontend.
It's worked really well so far at our scale. Eng team is fairly productive.
I'm less happy about the time I wasted on bash, DOOM WADs, and Desktop Linux. Yes these are are all a while ago. I didn't invest my time wisely when I was young.
I'm also glad I didn't invest in GraphQL, Kubernetes, Angular, Solaris, and perl.
One example that stood out to me though:
> GraphQL discourages breaking changes and provides no tools to deal with them.
GraphQL the standard doesn't provide tools no, but I've been very successful using Apollo Studio to solve this as (in my experience) the workflow maps to how you generally develop applications:
1) agree on some schema 2) make a (Apollo studio) "branch" with the schema change 3) mobile & backend devs (typically) code gen the objects they need for the schema 4) backend dev deploys a preview branch of their implementation, mobile dev points the client to it 5) test it, merge it, publish the schema on the main "branch" - deal with the breaking changes if Apollo warns you of them.
So maybe you can accomplish this with other tools, and maybe it's not fair to compare "the standard" to a particular tool, but I usually say I stick to gql (where appropriate) because there is a tool for it that works so well for the problem(s) I'm typically solving.
Would it be fair to say that GraphQL is extremely useful for internal-only clients? For example an inhouse data store, query service, test status monitor, etc?
So many issues disappear when you aren't concerned about bad-actors and you have _some_ control over both client and server.
Compared to what? If you're feeling really safe about the "internal-only" parts, just expose an endpoint to allow SQL (read) queries and you'll get essentially the same thing, especially if your data store already is SQL-like.
My first and last impression from GraphQL were that whoever wrote it hadn't had a chance to work with other query languages. A lot of the problems OP mentioned were quite on the surface. Had you ever used ORM, you'd be very intimately familiar with N+1 problem. Had you ever encountered SELinux, you'd be painstakingly familiar with authorization problems. Had you ever worked with XML (especially schemas), you'd be aware of parsing problems created by exploiting recursive properties of the grammar.
To me, GraphQL feels like a project by someone who is very enthusiastic, but lacks experience. If you need more examples of the same: the Terraform configuration language (not sure what it's called), Neo4j query language (I think it's called Cypher), libconfuse, Protobuf, and many, many more... unfortunately.
Google's entire software backbone is literally built on this haha. There are things about it I don't like, but it DEFINITELY scales
We don't have mobile app and don't even plan, but if we do, we always can implement some rest api.
Then I'm designing my table structure, optionally designing my views when I don't want a 1:1 reflection of how data is stored, setting up row-level security at the data layer, and making user-defined functions for the one-offs that deviate from plain CRUD.
But solutions like Spring DGS for Java, Graphene for Python, and Apollo for Node? No thanks. Never again. Way too much trouble and pain. I'd rather make lambdas that talk to the data store directly and output HTML than make and maintain a GraphQL schema manually again.
I really wish Postgraphile and Hasura were more popular, so folks could have skipped the low level plumbing and optimization fences like dataloaders that make GraphQL such a chore otherwise.
It really is elegant when you're not stuck in a swamp.
for whom? when was the last successful experience you had of telling a product manager to open their devtools and find the row in a websocket handshake showing the actual payload that went over the wire for the timeframe in question?
I am open to the fact that maybe there are super advanced organizations which have replay debuggers or Sentry or whatever that remove the need to utter the dreaded phrase "can you open the devtools?" but I regrettably haven't worked in one
At Firebase we chose GraphQL as the basis for our new Data Connect PostgreSQL product (https://firebase.google.com/products-data-connect) despite acknowledging pretty much all of the issues outlined in this article as correct.
GraphQL is an excellent IDL (interface definition language). It's compact, it's flexible (through directives), and there's literally no better way I'm aware of to rapidly construct complex nested relational queries. But the promise of "clients can fetch whatever they want" adds an enormous burden to backend developers because you have to secure yourself against queries of arbitrary shape and complexity.
In reality you don't want clients to "fetch whatever they want" because clients can't be trusted. The path we took is that developers can predefine the queries that are needed for their client, and then only those queries can be executed from an untrusted client.
This approach provides a surprising number of benefits - you get the flexibility of nested queries and field selection, the end-to-end strongly typed structure of a schema-driven API, and the ability to reason about security like it's a custom backend.
Made the dev experience a nightmare because I could never be sure whether it was my code or the client cache or the (actively in beta) server that was causing me to get back wrong data.
I've built platform which does just that: https://saasufy.com/
This approach has allowed me to create a library of highly generic components which can be composed into surprisingly complex front ends and where all data updates in real time (in a targeted, efficient and scalable way): https://github.com/Saasufy/saasufy-components?tab=readme-ov-...
You can build just about any front end you can imagine just by assembling these components. Almost no code needed. It takes me hours to build web applications which would take weeks or months to build. The real time update features come free. The dev experience is essentially bug free; any 'bugs' you may encounter have clear visual symptoms which can be 'debugged' by observing the HTML DOM.
I'm currently observing people getting hyped up over HTMX and it's kind of funny to realize that developers do actually like the declarative approach... And yet they're going in the wrong direction again. Just as they did with GraphQL.
It would have been impossible to do this with GraphQL because field-granularity/autonomy is essential. GraphQL queries combine different resources and fields together in complex ways and this makes it impossible to efficiently avoid real time update conflicts on the front end.
The simplicity makes it bad to use, if you work around the simplicity (arbitrary inlining, extra fields to choose what to inline, etc) then you end up with non-standard complexity.
Perhaps now it might be;
Nice to haves: Enough experience with GraphQL to never suggest nor implement it.
These are the kind of experiences I think which truly matter.
Looking back, it is hard to believe I spent a decade working in shops with no published spec, no code-gen. So many ugly surprises discovered in production, all of which were avoidable. Never again.
And for each issue he mentions that rest doesn't have said issue is basically because rest doesn't have the feature at all.
You could use graphql the same way as rest (by exposing queries without allowing to specify fields) and you still have a better rest, since at least the response has a schema out of the box.
GraphQL has a lot of advantages, the most important of which is data masking. In a properly structured GraphQL app, only the function that requested a field (i.e. included it in a fragment) sees that field. This allows many developers to move independently, without communication or coordination.
It's unfortunate, but there are lots of rough edges with GraphQL and it is hard to incrementally adopt, and so if you don't have enough developers (to have communication issues) and a team devoted to adoption, it might not be worth it.
Anyway, Isograph is a framework that seeks to take away many of those rough edges, while baking in stuff like data masking, etc. Y'all should check it out!
This essentially turns GraphQL into a DSL for implementing REST endpoints, which is still a useful thing since it allows to write the REST endpoint with only knowledge of the GraphQL API rather than knowledge of the whole backend architecture, which is generally useful if the backend and frontend are written by different people or teams.
That's the way Facebook uses it on their main website: they pass the query id in the "doc_id" form field, the arguement in the "variables" field, the server gets the actual GraphQL query based on the doc_id from some sort of internal dictionary and AFAIK no GraphQL query string ever goes on the wire in production.
That's already how it works, it is not an open ended SQL query. The GraphQL schema is the whitelist.
Something just never felt right about the client building the queries for me, I guess.
In my experience the use case is not limited to a single full-stack developer - this approach has turned our entire polyglot team into full-stack devs — no one is afraid of the data layer now. Super refreshing.
For public facing endpoints, "exposing an OpenAPI 3.0+ compliant JSON REST API" would be the first thing I'd reach for.
The problems with GraphQL where so obivious in the first 5 minutes that I looked into that. Looks smart and flexible - but isn't
I remember working on a Rest API and thinking about (things like) GraphQL... the typical "would it make life easier" and all that.
In the end, as the years have passed, I just stick to the minimum. If there is a tried-and-tested library or something.. I use it. When there is something new, I question it.
Never tried GraphQL. It looks like it can improve my data on one end, but cumbersome when it is hard to reason the data, or get generally complicated, which this article demonstrates.
But when you see those job ads with all these "great new technologies" it's hard not to fall into the trap.
Not sure if this will be good. This reads like they will add Vertical Tabs as a Sidebar, like all the other vertical tab-addons doing it now. But since the Quantum-update there is demand for a second sidebar dedicated for tabs, because as it's now, sidebar is really annoying to use.
But maybe it will at least add some improvements which the other addons can built upon.
> More streamlined menus that reduce visual clutter and prioritize top user actions so you can get to the important things quicker.
Oh gosh, no! Why make them even worse than they are already now?
Stick to tried and true - monolith, asp.net, angular or blazor front-end, relational database.
> asp.net, angular or blazor front-end
Since when are these not technologies pushed by big tech companies?
A company I worked with got badly burned by AngularJS.
I have never had any major issues or problems with it.
Think of it this way: GraphQL, Docker, and Kubernetes solve problems that very, very, very few GIANT tech companies have, but not every app will scale to millions of users.
As for how to tackle things today, I alternate between REST+OpenAPI and RPC models for communication. I am certainly biased as I have my own typed open source RPC library (Conduit) which is layered on top of arbitrary message passing transports such as WebSockets, but as of yet it's only suited for Typescript-based clients -- REST+OpenAPI is a better fit for an API with many consumers.
But for dynamic client/server and client/client single-implementor communication needs, I go with RPC.
- GraphQL performance issues
- GraphQL makes tasks more complex
- GraphQL schemas confuse junior devs, higher entry level
- REST cache easier
- REST if you understand what you are doing ... can do the same
- REST is better for error handling and tooling
Now in 2024, I clearly see LLMs gives much better autocomplete for REST or SDK code generated with protobuf ecosystem
There is not enough code repos based on GraphQL for LLMs to reason.
If you have like minded people who loves GraphQL, nothing can stop them but at higher and broader level it's a huge risk for dev velocity (like anything else if you dont know what you are doing)
The entire point is composition + client customization of the response body, but in practice the request schema is never modified. And even if it were, you could just version a REST endpoint.
GraphQL is never done "correctly," adds a layer of obscurity to monitoring and error tracing, and I've yet to see a case where it's actually the right tool for the job.
Maybe if you need to aggregate calls to multiple services into one, but if you're trying to avoid latency by reducing number of calls, you still eat that latency while the GraphQL server makes those calls for you.
GraphQL sucks.
However, you can go very far with a simpler version of it, just by allowing clients to specify what fields/relations they want and in what context.
I'm using a library that I've created for myself for years without any of the problems mentioned in the article.
The client side queries are generated by the server at compile time. Each request for an object requires a "segment" to be specified. On the server, each segment has the necessary filters/limits automatically applied to prevent data leaks.
The lie is that it makes things better. 100% of the time that I add an unnecessary thing to a project in the name of "it will make things better", it never did.
It's the old new-shiny, so here we are lathering on our dislike, which I feel is totally normal and expected. There's a new new-shiny around somewhere and a few years from now, I'll see articles like this one about it.
Having not yet read the comments, I plan to enjoy them thoroughly, I love a good hate-post about software I myself don't like. :)
I have been, like you, baffled by places that insist on using GraphQL for a biz software website that they barely support on mobile, or an app-only product with limited to 0 web support. But for situations where you want both a robust mobile app (sometimes multiple), and a robust web app (sometimes multiple), I don't know if there's a better solution that keeps the frontends and one true backend decoupled as well?
Curious what you say or what I may have missed for this scenario.
- https://github.com/rsinger86/drf-flex-fields
- https://django.wtf/blog/graphql-like-features-in-django-rest...
I am also over GraphQL but I really like the api explorers, code completion, type safety, etc.
Because of my experience, I feel that your position is making a slim distinction based on your preferences. All the tech you use is built for big corporations, why pick on one set of tech just because you don’t have the specific problems it solves?
For me, for example, K8s properly solves a bunch of problems for my small SaaS business, not least of which is that I can upgrade my three piddly servers without taking my customers offline. My SSL certs get upgraded automatically without downtime. My CICD pipeline is simple. Logging is much easier. And so on.
I don’t understand the disdain for modern, managed K8s at all.
For example, messages inside messages and messages in other "packages" can, accidentally be named the same, and then the author of such a definition will be spending a lot of efforts debugging such code because, without telling anyone, Protobuf parser (the one written by Google, other implementations behave differently) will prefer the one inside another message to the one inside another package.
To make this more obvious, suppose Protobuf had "package" separator, let it be ":". Then, you could define messages a.b:c and a:b.c. Then, there's no ambiguity. However, since there's none, and physically, the message a.b:c lives in b.pb file and a:b.c lives in a.pb file...
Another hilarious aspect is that fields inside messages are allowed to repeat (in the wire format). And the last one wins! So, using this easy foot-gun, Protobuf made streaming impossible.
Another tell is that Protobuf didn't have a formal grammar until much, much later. And once it was written, it was never tested on the real parser. I submitted a handful of tickets against that grammar because it was ridiculously bad. Simple and very common stuff like strings, that requires a little bit of sophistication (because of quotes and escape characters) was broken in the way indicative of someone doing it for the first time (and not even trying to test). The kind of screwups I saw my classmates do in our automata theory class.
It's wild and weird how such a poorly conceived "invention" gets enormous amount of attention and use (probably because of the company behind it).
The thing that I still _like_ about GraphQL is that it's a nice approach for expressing complex domain models over a protocol. If you are working with either REST or protos, you may still have to reason about graph-like structures but without the benefit of a graph-like schema.
It is often a poor choice for websites that should be cached, are publicly accessible and have simple and predictable data access patterns.
GraphQL has a fairly flat but very long learning curve which makes it a power tool that is great for those who have learned it in depth. Without that experience one is almost always better off using REST.
We've got little to gain, and the lack of flexibility from our POV is a relatively good thing. It gives us direct insight into desired use cases, and since the APIs are internal it lets us provide guidance on potentially better ways of implementing things as well as in some cases being able to provide direct optimizations for specific tasks.
I do really like the Api definition part of it though - but I found something like typespec now to be the perfect middle-ground, it allows out you describe your apis similar to a graphql Api without enforcing the graphql engine on you though.
Apollo federation and implementation of supergraph and nested graphs is pretty robust
We use both in production at reasonable scale and complexity 10+ roles few hundred object models, 100s of request/sec
We were basically just enhancing an external graph with some of our own stuff added on though so fairly straightforward.
Authorization: I do it in the database using roles, row level security and column level security. It works well and I defer everything to PostgreSQL's security controls, it feels like the right place to do it and I don't have to worry about it going out of fashion, PostgreSQL is here to stay. Anybody else who talks to the database directly is also subject to the same authorization rules, which is nice.
Introspection: this should really be disabled on production services. Only enable it for development.
N+1 problem: I don't really have a problem with N+1 because PostGraphile converts the request into an efficient query. In other cases this problem presents itself in REST too and the article proposes hoisting N+1 queries to the controller, but that's just really moving the problem around, and you can do this with GraphQL too.
The other problems, yeah sure they are present and a worry if you're running some highly visible/very loaded public API.
As someone who has used GeaphQL extensively, I really don’t understand most of the complaints, which seem like they’d be common to any complex API surface. Sure you can write a query that triggers a server bug, but that happens with REST too. Yes, your server needs to be hardened against these queries… so what?
And security is hard, granular security doubly so. If you need to do field level authorisation then the problem is that you need a policy engine, not a different query technology.
Then again having GraphQL as the definition for them is probably still not bad, I'll just have to write something that converts them to SQL::Abstract 2 trees once I get around to porting it to TS.
And you don't have to write something to convert them to SQL if you're using PostgreSQL, because Benje's already written it for you.
https://chillicream.com/docs/hotchocolate/v13/security
Honestly most of the "problems" the OP discusses has solutions in the documentation.
BINGO.
Someone (VP Eng who was a FE dev) 7 years ago decided shiny new thing was the best and we had to use it, it was owned by FE team, then no one wanted to own it, now BE team has to deal with it, and every dev goes out of their way to avoid it in arch design for new features.
Have seen this at two companies so far.
Basically, these are all solved problems.
My biggest complain is there seemed to be no way to just to query all fields. I know that is intentional and the point of GraphQL.. but they should support something for the server side to enable this. Maybe they have over the years, I don't know. But my experience was during the implementation phase the client kept adding new fields that I didn't know about and then I had to constantly ask them for the fields because I thought I was missing data. If I could have just queried ALL the fields, then saw what came in, and chop them down to what I need.. great.
The only way GraphQL seems to make any sense is if everything is basically completely defined and you are at a final project stage. After many many years of experience... this is rarely the case.
Cool piece of technology? Sure.. but hardly practical except in scenarios of extreme amounts of data and only when it makes sense for the client to return specific fields.
Although I think still for 95% of even those extreme cases, you just write a REST endpoint that returns the fields that make sense for the query....
GraphQL works pretty well when it's acting as a Backend-For-Frontend. The client can make a single call to get everything it needs at once, the BFF can then fan out to various microservices as needed. The frustrating part is when it's blindly used for something like a monolithic CRUD API with some light permissions. In that scenario you're taking all of the drawbacks, without reaping any of the benefits.
I'm really glad to be leaving this project behind as I move jobs, and I'm praying no one suggests using it in my new job. At least not until the industry more broadly understands it in more depth.
In this way services get freedom to define their stack while still neatly fitting into the suite of services, products get a tidy interface from which to query everything, and because the GraphQL consumer is more akin to a regular database consumer, the database muscle memory kicks back in.
I’ve also grown to prefer bespoke backends for each client over a super backend that tries to anticipate all of the needs of all the clients. It just opens too many holes and what it buys in versatility for the client author it also gives to the exploit author.
But at the same time it doesn’t have to be that bad. I don’t have this array of issues because I do: - query whitelisting for performance and security, - data loading to avoid n+1, authentication with whatever works(session cookies, tokens), - permission check based on the auth context in a resolver.
It works decently for us, allowing to stay away from getting into ESB. Yet have some shared domain, type safety, and easy integration of legacy and new systems/services.
I would say a bigger issue for us was to keep it all nicely organized / designed in terms of types and api contracts. But that’s manageable.
I have no beef against doing REST, jsonRPC etc. Actually I consistently steer people that way. But the documentation format we chose as an industry to build these things with, Swagger, is just disappointing. Some times I think the industry would be at a totally different point had we gone with more powerful standards like API blueprint (or maybe raml).
Case in point, I'm consulting an org with roughly 1k engineers right now on improving their API ecosystem and what we are seeing is that the more OpenAPI tooling they use, the worse the DX gets...
What are your recommendations? gRpc?
This right here is IMO the biggest advantage of a GraphQL system. What equivalent to GraphiQL is there for OpenAPI? With GraphQL my frontend devs can go shopping for data in one UI, with rich descriptions and strong typing and even try out the queries live.
However, lately I’ve been thinking that with the advent of React Server Components we will see a migration away from GraphQL-focused Frontend applications, and instead move toward other solutions. Such as ones based purely on exposing Postgres databases (e.g. supabase & postgREST) and type safe APIs (e.g. tRPC).
Authorization is performed by GRPC which returns only fields available to the user, rate limiting is performed on GRPC requests so at some point your data will start coming partially if you make too many queries or query that is too complex, N+1 problem is still there, but in a distributed system it's there even without GraphQL, the mitigation is caching in GraphQL server on GRPC request level.
In my experience GeaphQL really helped decouple frontend and backend and I'm pretty happy about it.
Besides GraphQL offers some standard way of making server side event streaming, it's not supported that well, but at least it's more comprehensive than bare web sockets.
I never got around to implement mutations though, individual change requests via REST are enough.
It's very true that a few years ago the gap was there, and people implementing GQL had to solve all these problems without access to these mature solutions.
But these days, they're mostly solved problems. Authorization by type that propagate through the graph is pretty simple. Rate limiting and complexity limits on queries is often built in the frameworks. Query parsing is solved with persisted query all the major frameworks have as first class citizen. Performance: lots of GQL caching solutions out there, and the "multi threaded by default" model used by most frameworks helps a lot.
Etc etc etc.
I jumped companies a lot, did both. For a while I too thought GQL was redundant, then went back to a more classic world after a successful GQL implementation. I had forgotten how many problems were solved, especially organizational and people communication issues, through GQL. And so we're moving to GQL again.
Someone in the comment mentioned GQL is a tech solution for an organizational problem. I'll say most good software tooling and frameworks ARE tech solutions for org problem, because technology is usually a solution to people problem. GQL is the peek of that, and it does it quite well. Don't use GQL to solve tech problems, there's better tools for those.
In other words, they cared more about ideal ways to access data than the product of that data.
This has so consistently been the case in my personal experiences that I avoid people in hiring interviews that start talking about or try to sell me on why I should switch my stack to GraphQL.
I worked on a team where 3 of us were well into our second decade of software development, yet we still had a consultant come in to help us sanity check our graphql implementations and ongoing strategy.
We were mostly on the right track. The struggles we were having were just… Normal.
At that point I really lost steam. Prior to that I was motivated by the thought that something wasn’t clicking yet. Discovering that I understood graphql just fine but it was typically a bad developer experience with obtuse tooling and queries took the wind out of the sails.
The worst part was mutations.
Writing graphql handlers in Rust was also awful. The more you try to leverage the flexibility of graphql, the more Rust freaks out because you’re doing exactly what you shouldn’t in such a strict environment.
Yet… Doing this in a language with weaker typing and less strictness seems like a potential minefield of bugs.
I see the appeal of graphql and I’ve liked it in small one-off situations where it was useful but had limited scope. Otherwise I genuinely hope I don’t work with it again.
It indeed seems like GraphQL saved your client in this case.
Yeah.. no.
Auth on leaf nodes, maybe I'm not understanding the issue but it seems solved without GraphQL. JWTs are one way.
https://www.graphile.org/postgraphile/debugging/#via-postgra...
Yes, that's why I said GraphQL and -corresponding- SQL, I was hoping to find something that showed me the SQL for each of half a dozen or a dozen examples ... though the debug option there will let me point the out-of-the-box CLI at a pre-existing database and have a look at as many examples as I like, so that's pretty close to what I was looking for.
Would also be interested to see a bunch of examples of what Hasura generates if you have those to hand (I'm going to poke through the Hasura Community Edition docs but if you have the specific FM to R handy ... :)
Anyway, here's an example with Hasura:
https://gist.github.com/dventimihasura/b3f3c9e7ef1442d8e7f16...
With most tech that I screw up I assume that "I wasn't using it right" but with GraphQL I'm not sure how anyone could. The permissions/auth aspect alone is a nightmare. Couple that with potential performance issues (N+1 or just massive amounts of data) and I want nothing to do with GraphQL anymore. Everything we attempted to fix our permissions issues just caused more problems. It would break existing queries and debugging GraphQL sucked so much.
If you only live on the frontend and someone else is responsible for the backend GraphQL then I understand why you might like it. From that perspective it's amazing, you can get as little or as much as you want with the specific fields you want. No waiting on the backend team to write an endpoint. However even then you end up saving queries as files or abstracting them (maybe IDE support has improved but it wasn't great last time I was using it ~5 years ago) and now you just have REST endpoints by another name.
At one point we considered whitelisting specific queries and that's when I knew we had gone too far and made a mess for ourselves. If we had taken the time to just write REST endpoints instead we would have gotten way more done and had way fewer grey hairs.
Now your backend devs aren't bored writing "business logic" and your front end devs aren't bored waiting for your backend devs. You have a new class of inscrutable errors and performance issues, but that's why you pay your backend devs the big bucks! Because some guys from a technical college couldn't possibly solve your issue, you need to pay 250k to people who went to Stanford or Berkeley.
Sometime in 2022 we switched back to REST endpoints for all of the reasons listed in the OP's article. Didn't hurt that we had hired for more fullstack engineers rather than "frontend only", so they saw exactly why we wanted to make the switch.
EDIT: to be fair, using Graphql and Hasura absolutely did help us iterate more quickly early on. But once we had a firmer idea of what we wanted to build, switching to REST was the right call. One of our most talented engineers wrote some helpers to make sure the frontend types were synced up with the backend types and that pretty much replaced the main benefit of using Graphql.
[0] https://hasura.io/events/hasura-con-2021/speakers/peter-down...
“ Any organization that designs a system will inevitably produce a design that mirrors the organization's communication structure. “
Your point about Resumé Driven Development, together with the dividing wall between front and backends is why FE frameworks have got so hideously and needlessly complex imo
The past few years I've been a 'full-stack' engineer - which is code for a backend guy who knows frontend.
In my personal taxonomy, a frontend developer is someone who cares a lot about UX, and making things look pretty, who also writes code.
I've met a lot of these people and they were more than happy to hand over all the infrastructure plumbing side of frontend apps to me - which I did along whatever REST API needed implementing on the server.
A good friend of mine is a solid developer generally, but he only works in AWS and while he leads a technical team, he doesn’t seem to have any idea what things actually cost in AWS.
He also seems somewhat susceptible to the hype trains that get started by AWS and customers of a much larger scale than his employer. He builds in the name of scalability but in ways that don’t necessarily address future organizational needs. I’ve seen this impact his work in ways that it isn’t my place to directly address, but that I know will come back to haunt his employer.
By way of example, he has built the service his current employer provides around the idea that each customer gets a different tenant that isn’t connected to any other tenant, and there is no ability even from their control plane to transfer data between tenants. His thinking was based on the idea from a prior employer where enterprise customers got their services managed in a customer specific AWS account managed by the company: total isolation. That made a lot of sense at his last two employers, but for the industry in which his current employer operates it is an anti-pattern. To draw an analogy, it would be like building an EMR that doesn’t have the ability to output patient records in a manner that another EMR could ingest. In his industry this sort of portability of end user data for his employer’s customers is both customary and expected.
This means his company has to build some kind of abstracting service that can enumerate and communicate across all customer tenants to shuffle data around or export it. It isn’t a capability anticipated in the architecture, but it’s a basic need.
Down-thread there is a reference to Conway’s Law. You can argue this kind of thing is a manifestation of that concept. My friend has never worked in this specific industry before, and so he just doesn’t understand their needs. He talks about it in purely AWS Well Architected terms and designs based solely on that for everything. That may be his job to an extent, but I think the broader problem is that no one in his company clearly communicated to him predictable end user expectations that impact architectural design.
Because it is :')
"Maybe implementing CORBA for message passing is over complicating it." "Maybe using OOP and facade classes is over complicating it." "Maybe using XML to store all the config information is over complicating it." "Maybe using this ORM with a strange file based caching mechanism is over complicating it."
And always get drowned out by everyone going with the trend.
That simultaneously makes marketing value and drives a lot of silly decisions. Not much to be done though, humans are human
I spend loads of time on LoB apps, still rocking Apache prefork to CGI. Does it scale? Sure, to all 3200 users company wide. Everything it's boring. Caching? Never got in the Memcache vs Redis fight later. 10yr after that? We picked Redis for the case where it had proven to kick ass.
Did you know that PHP5.4 apps can still generate profit in 2024?
Joking aside, I'm sorry that happened to you and I'm sorry for the people that took over the system I helped to write.
The problem I always had with rest was that nobody really follows any patterns, not in the same company, not in the same project. There are a million different decisions you can make with rest and if you let a dev alone to build it themselves you're gonna get yet another variation, whereas GQL is only implemented according to a spec.
The N + 1 problems are pretty much fixed these days & mostly any dev can build something in themselves to fix it if they want to. Permissions/auth is relatively easily achieved with middleware and directives, though it's also totally possible to roll your own by writing something that inspects the querys AST if you really need to have your auth layer separate to your schema.
GraphQL feels like magic when you first start with it (which should be a red flag) but once you need to support more roles or sets of permissions and as your business logic starts to creep in things go haywire. In my experience things that are easy up front are unmanageable once business logic gets added in. For straight CRUD it's amazing but very rarely do our apps stay as just CRUD and that's when things fall down. For example, on create of a new user I need to send a welcome email. It's been 5 years since I was working on that GraphQL project but I have no clue how we'd handle that. I'm sure there is some kind of a event system we could hook into but with REST I just have a simple endpoint that saves the data to the DB and then sends and email (or puts it in a queue), way easier than in GraphQL. Again, fetching and updating data is easy until you need to handle edge cases. I have the same feelings about Firebase and friends. Feels like magic at the start but falls down quick and/or becomes way too complicated. GraphQL feels like DRY run amuck, "I have to keep writing CRUD, let me abstract that away", ok but now if you need special logic for certain use-cases you have a mess on your hands. Maybe GraphQL has ways to solve it but I'll bet my hat that it's overly complicated and hard to follow, like most of GraphQL once you get past the surface.
I'd love to see a "Pet Store" (I think that's the common example I've seen demo'd in REST/Swagger/GraphQL/etc) example with heavy restrictions based on different users/roles. It's like using the "Todo app" example in a framework, sure that works and is straight forward, I want to see how you handle the hard stuff and if it's still easy.
A while later, suppose someone adds some connection from user to, say, orders. The person who added orders to users was kinda lazy and assumed (somewhat correctly, at that moment anyway) that permissions weren't an issue. So there's no additional permission checking when fetching the orders connection.
Now, suppose 6 months pass. Some other engineer is now implementing reviews. Each review must have an author. What do ya know, there's already a user object available in Graphql. How convenient!
Now every user can inspect all orders of every other user, if that user has left a review.
Mistakes like this are all too easy with graphql, and is the number one reason I would never consider using graphql without a query whitelist.
With ad hoc solutions like tRPC, you end up fetching the same field multiple times (and probably doing some sort of network waterfall), or you give up on data masking and composability. And if you have enough engineers, data masking and composability are critical to maintain velocity.
Use of persisted queries also addresses the article’s concerns about DDOS.
Of course the documentation on some kinds of query syntax was too sparse, (this is for Shopify) but I could see how it might be nice for certain kinds of cases. If you run a platform it might be a good option to offer in your API. For shopify afaik there are equivalent calls in both REST and graphql so you have options.
It's not that simple, new features are add to GraphQL only, some other things are REST only,some APIs work differently (like product search by title, in REST it have to be an exact match, in GQL it can be partial match)
It provided an escape hatch that allowed rapid prototyping, and came with a default UI, and then we cleaned up the ones that were worth it.
Though I guess you can do that with REST too.
I'm currently exploring all of this myself. I have a side project in mind that can use a graph db, and I thought a front-end graphql can work well with a graphdb backend. I was not sure why this pattern is not more popular, but reading all of this now, I'm seeing where these problems may arise.
A graph db backend can use efficient graph search algorithms, especially for deeply nested data, but the issue with authorization is still there. If anything, fine-grained authorization is something better represented with graph dbs than with relational databases.
And perhaps not coincidentally, React introduced "server actions" as a mechanism that is very similar to that. Engineers can author what looks, ostensibly, like frontend code, merely splitting the "client" side and "server" side into separate annotated functions, and the React bundler splits those into client code, a server API handler, and transforms the client function call into the annotated server function into an HTTP API call.
Having used it for a bit it's really nice, and it doesn't result in yielding so much control to a very complex technology stack (GraphQL batchers, resolvers, etc. etc.)
I think this is what a lot of people end up doing (and yes, with REST). Translating options via query params / POST body into a query. In theory GraphQL was supposed to mitigate this DSL-like translation, but the thing is people like flexibility and ability to change and, yes, break backwards compatibility. That's also why a lot of people end up with a translation layer with things like RPC, which is itself supposed to be a direct, shared communication protocol.
The messiness of APIs is often a feature, at least internally. These approaches that attempt to avoid the mess are better for the end consumer but cause friction within development groups and the benefits are often obscured.
I've had my share of headaches with the various flavors of ORM and GraphQL and always come back to query templates, e.g. MyBatis in the JVM ecosystem or Go's template package. There is still value in abstracting this from the REST web service interface to make it possible to change the app<->database connection without disrupting REST clients. It's possible to reuse parameter structs/classes between the REST client and DB+template client layers to avoid a lot of rote translation. It seems simple and repetitive, but actually saves time compared to the GraphQL/ORM complexity as apps & query complexity scale, in my experience.
https://www.edgedb.com/blog/edgedb-5-introducing-passwordles...
Like a stored function in postgresql?
Worked pretty well. Definitely something that could be make to. Kind of graphql themed but how it translates to REST can be explicit.
In both these projects the GraphQL had started small. I came in during a more mature phase of these projects (2 and 4 years). That's where the requirements are harder, more specific, and overall complexity has grown. Adoption and demand on the API were growing quickly. Hence you logically spend more time debugging, this is true for any codebase.
But GraphQL has everything in it to make such problems even harder. And both these projects had clear signs of "learning-on-the-go" with loads of bad practices (especially for the N+1 problem). Issue descriptions were much vaguer, harder to find in logs and performance issues popped up in the most random places (code that had been running and untouched for ages).
Fun fact; in both these projects the original devs who set it up were no longer involved. Probably spreading their evangalism further elsewhere.
RPC and REST are just more straightforward to monitor, log, cache, authorize and debug.
One thing the author doesn't mention is that you can limit the set of queries clients can call in a GraphQL service, by hash or signature. This mitigates a lot of the gnarly performance and security issues because the attack surface goes from "arbitrary queries" to "queries you've already 'vetted'", where you can look at things like complexity, ACL behavior, etc ahead of time. Since clients (in my experience) aren't usually modifying GQL queries at runtime, this is a pretty good tradeoff.
All that said, I find Buf Connect to be the best set of tradeoffs for most projects: strongly typed servers and clients, strong ecosystem support around protobuf (e.g. to generate an OpenAPI spec), a standard HTTP/JSON interface for easy curl et al compatibility, etc.
OpenAPI as the source of truth is annoying because it's too flexible, and it's rarely possible to generate type-safe servers + clients from an OpenAPI spec without running into one edge case or another.
It works there because
1. Every user is logged in. Is there anything you can do at FB without giving up something to the Zuck?
2. Because it's all behind a login, you can front load the first login/request with a giant SPA and then run all the custom queries you want.
3. everything at FB is some sort of blended context (my user, someone else's user, a permissions interaction)... security is baked in to every field.
4. Because of permissions, and login requirement it's hard to be a bad actor (FB just locks you out, nothing is public).
If you have a SPA and logged in user requirement and that robust permissions model then GraphQL might make sense... Otherwise its a shining example of conways law and might not be fit for your org... The same can be said for react too.
IMO GraphQL is a technological dead end in much the same way as Mongo is.
They were both conceived to solve a perceived problem with tools widely adopted at the time, but ended up with something which is even worse, while the tools they were trying to replace rapidly matured and improved.
Today OpenAPI REST and Postgres are rightfully considered as the defaults, you even have PostgREST combining them, while most of those who adopted Mongo or GraphQL have either long migrated or are stuck discussing migrations.
These days, given the freedom to write the backend in TS too, I might look into tRPC instead. One thing's for sure, I won't be going back to OpenAPI unless and until I can fully autogenerate api.yaml and otherwise never have to touch it again (getting there with zod+openapi on another project, but it's nowhere near as easy as graphql-codegen doing all the things with one introspection query).
1. GraphQL was and remains insanely hard to build without an underlying data layer that does the heavy lifting. Without projection push-down, predicate push-down, a data layer that can support heavy parallelism it’s untenable. Exactly the problems the OP highlights - needing to “hoist”…
2. GraphQL on REST is an anti-pattern. The hype takes you there, but the juice is not worth the squeeze. The problem was lack of types? Add openapi. The problem was custom aggregation endpoints? Make it super easy / cheap to build aggregate endpoints in REST. Use an AI copilot to write an aggregate REST endpoint and a openapi schema for it even. But maybe the last thing to do is to build annd mainatian another API layer with a completely different execution model.
It’s not what it was meant for perhaps, but GraphQL’s killer use-case is an API to access / operate on data. Especially when there are multiple consumers of data (services, apps) and they don’t own the underlying data sources or speak the underlying language of the database. This turns out to be the underlying problem behind a lot of api, data modernization / migration / decomposition efforts.
The cost of this approach is implementing Graphql by building a compiler/planner with a robust authz system baked into it. A resolver based approach can never cut it, unless you resolve a query plan - aka build a compiler.
If you want to use graphql to just batch rest endpoints, it’s very likely going to become legacy tech as soon as the team that built it starts to move on.
Yates implements Postgres RLS along with Prisma, which we use as our ORM, and then our GraphQL schema is generated using TypeGraphQL (https://typegraphql.com/). Overall, it's a very nice setup and allows us to be versatile on the client side while still having strong authentication integrity.
While perhaps not as polished as Hasura, this stack does have the nice benefit of being free ;-)
Yes.
- If data already exists in cache, a query will return that data instead of making a network request.
- Everything that has a data dependency on something in the cache will automatically update when the data is updated, e.g. after a mutation.
- Cache data can be optimistically updated before the request completes, UI that queries this data will automatically update.
- Components will automatically refetch data if they need to, e.g. if an object is partially updated.
The pain points are pretty painful though:
- Really hard to debug unexpected refetches.
- Normalizing the data for the cache comes at a cost, it can be pretty slow for big responses.
- You quickly realise you need to really understand how the client works under the hood to be productive with debugging/complex behaviour.
I see it as a case of "this is the worst API/client, except for all the others". I'm curious to hear how people using non-graphql APIs are managing data in the client in web-apps with complex data needs?
[1] https://www.apollographql.com/docs/react/why-apollo [2] https://relay.dev/
Reliability:
* Not null fields in a distributed system are a lie. Clients write code assuming something is not null, so a query that fetches data from N sub systems breaks the entire page when one of them fails.
Performance:
* People say you only need to fetch just what the page wants but in practice clients create re-usable fragments for every object in the system and use it everywhere. Any time a new field is added, every api call fetches that new field adding latency everywhere
* clients are unaware of the underlying topology and add fields that are usually harmless but have bad tail latencies.
* The completely generic nature of the API means the backend can't optimize performance for a specific page. E.g. if one API has nasty tails, but it's not that important for this page, the backend could time it out at some reasonable value instead of holding up the entire request
GraphQL is a protocol and you define the implementation. Some GraphQL implementations like REST implementations try to generate everything for you. That is not "GraphQL" but one type.
GraphQL is way to query nested APIS. The dataloading N+1 Problems are substantially easier to solve in GraphQL and many frameworks have solutions auto-optimize ORM queries for example.
The backend defines the query, the frontend requests it. Simple. Never understood the hate against GQL that now the frontend has all this power. They have exactly as much power as you would have exposed in a Rest Interface just now the backend can actually see all the data it needs at once and optimize.
If you are worried about a cartesian product from a GraphQL call I have news for you about production REST systems. Ever seen an engineer do a loop and make n+1 REST calls for resources? It happens more often then you think.
REST encourages resource waste. You are getting fields you don't need. Hard to query related objects, etc.
Benefits I have reaped with GraphQL:
1. API analysis - I can statically analyze a typescript program and verify their API calls are valid against backend schema.
2. Usage analysis - Statically analyzing the schema I can see which fields are still in use and safely refactor.
3. Frontend Velocity - The frontend can cange its data needs on the frontend query whatever related objects it needs efficiently without backend changes. You can get all data for a page with 1 call and not have to have page specific endpoints.
4. Less backend engineers are needed as API changes less.
5. N+1 Optimization much easier to solve in GraphQL then REST
There are so many advantages to using GraphQL. The only advantage of REST I can think of is for static external APIs.the triky part of gql is we need to build a Query system for all business requirement in single entry, and we can not predict what query will be issued by client.
this is anti-pattern because presenter layer should not care about how data is composed.
It would be much easy if we treat each rest/rpc endpoint as a GQL entry, use resolver and dataloader to quickly & easily build complicated view data, everything is still under the control of backend.
here is a demo. https://github.com/allmonday/pydantic-resolve/blob/master/ex...
The one positive to come out of working with it (aside from knowing how to spot a tech black hole) is that it informed the design of the API layer in my framework [1][2]. I realized the sweet spot is starting with a basic JSON-RPC type endpoint and then layering things like input validation [3], authorization [4], and selective output [5] (only requesting certain fields back) on as you need them.
[1] https://docs.cheatcode.co/joystick/node/app/api/getters
[2] https://docs.cheatcode.co/joystick/node/app/api/setters
[3] https://docs.cheatcode.co/joystick/node/app/api/validating-i...
[4] https://docs.cheatcode.co/joystick/node/app/api/authorizatio...
[5] https://docs.cheatcode.co/joystick/ui/api/get (see output array in the function options API)
There's plenty of other sites / services that receive almost as close to FB properties in terms of traffic yet you never hear them pushing all those tools. Trading firms, Porn firms etc. Some just use REST + JSON or RPC + JSON.
Wish us an industry would read Joel's Spolsky's Fire and Motion article: While you're fighting tools built by FB you're not making stuff for your customers.
Revenue / Profit >> Tech
I'm glad Redux hype train is over and nobody is using it on new projects no more.
I’ve been saying this for years: fetching multiple things in one query is not something normal-scale apps care about. What devs like about it is client generation and type safety. So OpenAPI, for all its flaws, covers that. GraphQL’s schema language is much more beautiful — hopefully Microsoft’s TypeSpec will take off and we can have the best of both worlds.
Another point implicit in the piece but not quite stated is that GraphQL aims to make something nice for the API consumer, but the implementation side is a nightmare. It is not worth the tradeoff because eventually, that nightmare leaks out to the consumer because it is too hard to make improvements to the API.
First, some of these issues--authorization, security, N+1--can be mitigated by using something like Prisma, PostGraphile, or Hasura, instead of crafting GraphQL backends with code.
Second, there are gains to be made by compiling a GraphQL operation to a single operation in the underlying database's query language (e.g. SQL)--when that's possible--rather than by following the "resolver and data-loader" catechism.
Third, as I've written elsewhere recently, I think the N+1 problem is overblown. Not that it doesn't exist, but just that it only sometimes exists and usually isn't as bad as is often claimed. But again, this is eliminated by switching to a compiler approach anyway, so it's not worth making a federal case over it.
Despite all this, like I said I'm still over GraphQL. If you must implement it, try to use one of the tools mentioned above if you can.
Same problem with Prisma Model definitions and other such things.
Please, if you make a new thing and it fits neatly into a data format, use a data format! Let me use all of those well established libraries, schema definitions and programming concepts in order to generate, parse and make sense of your thing. Let me seamlessly write your language with the data structures I already know in my language if that's possible.
Don't make it pretty, make it usable.
This isn't even close to valid json:
{
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
}Let me explain the problem GraphQL actually solves. FB, as we know, is an incredibly large mobile app, possibly one of the largest in terms of actual code. Here are some realities about mobile apps:
1. Once released into the wild, that app version is out there forever. At app installs in the billions this is a serious problem. So you need something that handles versioning of your API. You need something to force you think about versioning and support old versions as long as possible. Again, I don't see the word "version" anywhere in this post. Versioning doesn't seem to be a problem the author has;
2. There are a lot of common objects in the FB app. Posts, comments, etc. When these objects become sufficiently complex, you don't want individual teams pulling out random fields. This is one thing fragments are for. It allows a specialized team define the object model and allow other teams to pull out a subset of that data.
3. FB uses an in-memory graph database for almost all things so issues like N+1 queries (which are real issues if you're talking to a relational DB) don't really come up. The in-memory database has a layer over it that does things like enforce permissions and privacy policies on reads and writes. GraphQL auth is really a superset of this. So if you're querying an endpoint for a user and their blocked users (one example from the post), you probably won't have auth in your endpoint because that'll be enforced by the data access layer that already exists and be written and maintained by a team responsible for that data.
Some comments here have complained that GraphQL is a technology for an organizational problem. I would counter that by saying all technology ultimately is tied to organization. They affect each other.
The above was all done to avoid things like privacy leaks, which at FB's scale is a real problem. Speaking from experience, a significant amount of computing power and software engineering time is tied to avoid these problems by the teams responsible as well as other teams to try and detect an unintentional leak.
How I see a bunch of people use GraphQL (not necessarily the author of this blog post) is as a 1:1 map to a relational model beneath it. That doesn't make a whole lot of sense. GraphQL probably isn't for you.
For example, having nested queries more than 2 levels is a no go for me (just like having nested inheritance is basically anti pattern)
Focus more on your interface. One way to avoid N+1 and nested query is to required parameter for related fields. For example
```
user(id: $userId) { {
id
friends {
id
...
}
```to
```
user(id: $userId) {
id
friends(id: $userId) {
id
...
}
```I wonder if GraphQL would have been as popular if it was a much smaller shop than facebook launching it. Feels like having a name like FB gets you a tech credibility pass.
If you have two smart layers adjacent to each other (and GraphQL is a smart layer) then the interconnection between the two and the conflicting abstractions of data becomes an issue.
By having something dumb (REST endpoints) between the business layer and the complexity of the front end, it is possible to have reasonable abstractions writing to the REST endpoints and an abstraction of the payloads that the endpoints provide into what is needed in the front end application.
It seems that GraphQL works best when the backend has minimal business logic and the thing that is calling GraphQL likewise has minimal logic -- and all the logic is contained in the GraphQL query itself.
But if you're finding complexity in getting things into GraphQL and manage permissions and mutations... or you've got the complexity of the front end where the data model the front end needs to work with doesn't align with the GraphQL model ... then you've got complex solutions abutting each other and those spots is where the pain will be found.
6 years. For a lot of people, that was also the time ( 2013 - 2019 ) they moved from SPA or Client Side Rendering and started looking or move back to HTML+ approach.
So may be for any company operating on Boring Technology principle, you should not choose any hyped tech until they have been battle tested by the market for 7 years.
So in general had the same feeling about graphQL because I still had to write layer of code that gets stuff from database, get it limited or paginated. Maybe once you have enough endpoints then you can change your front end against already existing GraphQL - but for me that was never the case as 90% of work is adding new tables, new endpoints so graphQL feels like additional work with additional footguns for almost no benefits.
REST API's are a proven solution for the problem of other apps, including front-ends, needing data from a data store. Using JSON is much improved over the days of XML and SOAP. Beyond that there haven't been advancements in technology that cause fundamental shifts in that problem space. There have been different opinions about structuring REST calls but those aren't going to cause any real forward progress for the industry and are inconsequential when it comes to business outcomes.
There are so many developers out there that can't stand plugging in proven solutions to problems and just dealing with the trade-offs or minor inconveniences. Nothing is going to be perfect and most likely a lot of the software we write will cease to be running in a decade.
Ever seen an engineer do a loop and make n+1 REST calls for resources? It happens more often then you think because they don't want to have to create a backend ticket to add related resources to a call.
With internal REST for companies I have seen so many single page specific endpoints. Gross.
> There have been different opinions about structuring REST calls but those aren't going to cause any real forward progress for the industry and are inconsequential when it comes to business outcomes.
You could argue almost any tech solution in a non-pure tech play is largely in consequentially as long as the end goal of the org is met, but managing REST APIS were a huge point of friction at past companies.
Either it goes through a long review process to make sure things are structured "right" (ie lots of opinions that nobody can sync on) or people just throw up rest endpoints willynilly until you have no idea what to use.
GraphQL is essentially the "Black" for Python Syntax but for Web APIs. Ever seen engineers fight over spaces vs tabs, 8 vs 4 spaces, whether a space before a colon? those fights happened a lot and then `black` came out and standardized it so there was nothing to fight over.
GraphqL makes things very clear and standard, but can't please everyone.
Much like CSV, JSON isn't particularly standardised and different parsers and writers will do different things in some situations. Usually it doesn't matter, but when it does you're probably in for a lot of pain.
If you handle structured data and the structures might change over time, JSON isn't a good fit. Maybe you'll opt for JSON Schema, maybe that'll work for your use case, but with XML you can be quite sure it'll be reliable and well understood by generations of developers.
The tooling is generally very good, commonly you can just point your programming language to the XSD and suddenly you have statically typed classes to program against. Perhaps you'd like to store the data in a RDBMS? You can probably generate the DB schema from the XSD. If you want you can just throw JSON into MongoDB instead, but there will be very important tradeoffs. Same goes for UI, you can write some XSLT based on the XML schema and suddenly you get web views directly from API responses. Or you could use those classes you generated and have your GUI code consume such objects.
None of this is as easy with JSON as it is with XML, similar to how many things aren't as easy with CSV as with a RDBMS.
If only that were true in my experience.
It allows teams to work with less communication overhead. It solves more of a human problems than a technical problems, if someone think there is no value in that and bare metal performance is paramount that person never worked in a big org.
> RPC and REST are just more straightforward to monitor, log, cache, authorize and debug.
In some ways yes, in others no. For example it can be near impossible to see if a deprecated field in a REST API is still being used and by which clients it is being used. With GraphQL this is fairly simple.
Unfortunately GraphQL way of working is very different from normal REST APIs and often requires more complex server-side caching. The N+1 problem needs to be figured out upfront for every data-storage system used in the backend.
That's a huge bet, especially given that GraphQL is expensive in the first place, and given that the more you grow the API in size, the less you can actually map the cartesian product of all request params.
It is far better for the Backend to provide Frontend a contract--can do it with OpenAPI/Swagger--here are the endpoints, here are the allowed parameters, here is the response you will get--and we will make sure this narrowly defined scope works 100% of the time!
What do you mean by "backend developer" ? The one who creates the GraphQL endpoints for UI to consume ?
You should log deprecation warnings.
But also if the client is composing urls/params manually then you are not doing REST, you are doing RPC.
Rest APIs should mainly use HATEOAS hyperlinks to obtain a resource. that is clients almost always call links you have provided in other reponses (starting from a main entrypoint)
Ah this brings up bitter memories. Team I was managing was roped in to become the first graphql framework (nay platform) the ivory tower (central architecture run by the cto) team was building and trying to shove down the rest of the company. This was during the graphql craze around 5 years ago. The principal engineer leading it was even preemptively promoted to distinguished engineer for future contributions.
Fast-forward 5 years project was disbanded due to massive migration, cost and complexity problems. DE still lauded for experimentation heroism and evangelism. I think he is now pushing the latest flavors of the month to go for the next promo!
If I use graphQL again it’ll only be for admin features. Anything where very few users will use it and very infrequently. Preferably in spots where caching works against the workflow. OLAP vs OLTP.
GraphQL is really about reducing friction between teams. High functioning distributed systems all have two qualities in common: work stealing and back pressure. Without back pressure there is nothing to stop the project from running off a cliff.
I think the "learning-on-the-go" symptom, where you can sometimes literally read down a file and watch some developer learn the language as they add more and more functions to the file with a gradual increase in skill (or, to put it less charitably, as they slowly get less bad at writing code) is probably a very common thing, and not just a GraphQL issue.
I think two projects having loads of bad practices is too small a dataset to really assume anything, you sort of need to see widespread "bad practices" in the tech to be able to determine that the bad practice is actually the norm practice and there is perhaps a flaw in the tech that encourages that norm.
"The idea of it" is sometimes fine, but then there's also "the practicality of it", and sometimes that's a very different thing.
Remember the old microkernel vs. monolithic debate; everyone more or less agrees that in principle, a microkernel is better. But the practicality of it is a lot more complex, so monolithic kernels and hybrid ones are much more common. Microservices vs monolithic is essentially the same debate, and I've seen a lot of Microservices with very poor implementations and a lot of problems. That doesn't mean the idea is bad in itself, but if it's hard to execute well, then you do need to be very careful.
There's tons more examples of this. You also see this sort of thing in e.g. politics, where what's "more fair" vs. "what's actually achievable without introducing heaps of bureaucracy and overhead" are sometimes very different things.
In the case of GraphQL, I think it's pretty obvious that the general idea, as described from a high level, is a good one. But the practicalities of it are a lot less straight-forward, as this article explains reasonably well IMHO.
The only downside is if one of those unused fields changes due to a mutation then all components using that field will rerender (ofc I'm assuming React here). Again, not the biggest concern if you've got your memoization set up correctly
Overfetching or not, that's a rather big difference.
Surely there are some good use cases.. just so few and far between. No one should be using GraphQL unless absolutely necessary.
Then it's just REST with extra steps and none of the benefits
The best practice for GQL is to make frequent, small, queries (Apollo handles batching them) throughout your application. Apollo won't do any extra work to fetch new fields if they're already in the cache
Not to be that person because I understand there's always edge cases, but in general with GQL if your queries are highly complex or too nested "you're doing it wrong™"
using OPENAPI, rpc, GQL types in client, etc to share typing (schema) information between client/server
resolver/dataloader in GQL, eager join in ORM is to handler internal data composition
presenter layer should not care about data composition, so that writing Query at presenter is an anti-pattern.
presenter should fetch schema info & data passively, like what https://github.com/hey-api/openapi-ts did, the job of implementation belongs to backend.
In fact what rest/rpc really need is the resolver and dataloader, to help backend easily extend or composing data together, and immediately transferring the schema & data to clients.
pydantic-resolve is the python binding for this idea.
No. With RPC we can just make a HibernateServer call and be done with it.
For most people "security is baked in to every field" is going to be very expensive.
That having been said, outside that data model, your absolutely correct that its going to be costly to maintain those extra layers of relationships.
People completely missed the point of GraphQL, which is you TRADE flexibility for the client for added cost on the server.
Which in a app and team as huge as facebooks' made sense, especially since they have the so-called facebook apps that could do... anything.
I mean, isn't this THE selling point of GraphQL? How was it missed so badly? I think every elementary resource about the technology covers this in the pros and cons section...
At least GraphQL supposedly works for Facebook, and I tried it out before deciding it wasn't a default. I never even bothered with MongoDB. I've had to repeatedly veto using both in projects, cause someone thought it'd be cool and thought that was a good enough reason. Finally it's not cool anymore, but there will be another thing.
I swear, the older I am, the more convinced I am that people who don't use a RDBMS just don't work on complex systems. Period.
* openapi was basically nonexistent when GQL came out. It certainly wasn't "the tool they were trying to replace"
* Postgres and GQL are not in any way mutually exclusive
* Today, openapi is still tiny compared to GQL. At least as measured by StackOverflow question tags:
https://trends.stackoverflow.co/?tags=graphql,openapi,soap,m...
Can you suggest alternatives to graph introspection and related UI tools like GraphiQL, and the subgraph federation systems?
OpenAPI 3.0 has this concept of remote references, which can be URLs to other OpenAPI specs hosted anywhere. https://swagger.io/docs/specification/using-ref/
No analog for "subgraph federation systems", unless a load balancer will suffice.
I found myself spending a large amount of time inventing and trying to patch in solutions that most RPC and REST frameworks solved long ago for both the server AND the client (auth, rate limiting, error handling and validation stick out particularly). Client solutions are comparatively heavy, complicated, and riddled with gotchas (e.g. caching) that trip up new team members more than REST. It’s not impossible to build performant GraphQL solutions, but the solutions feel more like afterthoughts and require more vigilance to ensure your team doesn’t stick their finger in an electrical socket compared to REST. The lack of namespacing or organization results in almost unintelligible query and mutation documentation for large projects. The comparatively large size and complexity of requests can be a headache for ops teams. I loathe that interfaces and inheritance don’t work for mutations. Front end devs just use it like a very heavy REST and the holy grail promised by stuff like Relay never materializes. I could go on.
And at the end of the day, the app’s API usage will stabilize and mature, and the expressiveness becomes less compelling compared to its cost. When I went back to OpenAPI and REST, it was like a breath of fresh air, I felt I was building things much faster. I will grant you that generating clients from OpenAPI still is the worst part.
I got all that for free with API Platform because it's based on Symfony. Ironically it's the graphql implementation that's primitive [1] -- but rock solid, so it won out, and being a rank newbie at GQL when I started, it was probably best I was stuck with the basics.
The JS backend world is a lot more ad hoc than the modern PHP world, so I can picture a lot more nightmare integration scenarios there. Besides, I'd probably prefer using tRPC + zod for my next all-TS project.
--
[1] - It's actually pretty sophisticated underneath, but the code is a loosely-documented architectural maze, so yeah.
This is the difference
It makes UI changes much much easier to deal with.
Deleting code automatically removes its data dependencies from the root query, it's ideal.
I would say the DX is pretty much comparable to using Apollo Client.
You could use TanStack query with GraphQL, Apollo, REST, or any other data source.
If something is null that's not supposed to be null, then the entire operation should be called into question. It's probably not safe to proceed so it's a good thing he entire page breaks, you don't want users to continue based on wrong information. If you define something in the schema that it's possible that it's null, but then the frontend dev ignores the fact that it can be null, why is it GraphQL's fault then that the page breaks?
* clients create re-usable fragments for every object
As a frontend developer I don't know why you would do that, but if your frontend devs are doing that then yes they are doing it wrong... However switching to REST with statically defined endpoints doesn't solve the over/underfetching problem, but as backend developer you do get to gatekeep that aspect. So yeah the devs should really be just doing it right.
Note that the error types added to the union should only be as granular as relevant to the client. Most places will be just Foo | FooNotFound | FooError because your UI doesn’t care why there was an error and you don’t want to unnecessarily leak backend info when it’s not relevant.
I wish this was more strongly recommended in the GQL org docs, because so many people learn it the hard way and migrating is not easy.
I quite like Relay's pattern where components define their data requirements, and this is passed up the component tree to some query at the root. Avoids a situation where the query defined at the root asks for unnecessary fields because it's so far away from where the data is actually required.
https://relay.dev/docs/principles-and-architecture/thinking-...
I can't imagine a road crew getting away with spending an extra year to build a road because they decided to use completely nonstandard equipment that doesn't work well for the task or they don't know how to operate. I especially can't imagine the road crew screwing up multiple jobs in a row because they change equipment every time they're starting to understand the current equipment.
Maybe it does happen though and I just haven't seen it since I'm not in that industry.
That was actually a very small parts of the projects in the world at the time, and in fact, a very small part of the number of projects that adopted react at the time.
I remember above all that:
- React was hyped to the roof by facebook. They had a fantastic marketing machinery for that.
- React sucked for years, with a terrible doc, a crippling webpack experience and breaking compact all the time.
- The JS community was moving from koolaid to koolaid, never assessing the new tech for their cost. They solely inflicted on the world slow and brittle preprocessors left and right, thousands of stuff you had to integrate manually because "libs > frameworks", and jumped on react, redux, graphql, docker, spa, microservices.
So I would say it was a loooot of hype for react, just like it was for graphql.
I'm going to feel like spamming at this point, but, remember when XML was the future?
So devs respond in kind with equal amounts of bullshit.
It's a cycle of bullshit in the industry.
I also think there’s an avoidance to simply “translate” a GQL query into an SQL query. Not that it can’t be done, but it allows a lot less flexibility in the backend as far as code patterns that can be adopted. Basically it minimizes the use of ORM models, which may be a pro for some and a con for others.
I haven’t worked with GraphQL in over 4 years since I left my last job. I actively made a choice not to use it at my current job and steered the ship towards REST endpoints, mostly because it would be easier to build authorization middleware. Also like the author of the article discovered, code littered with dataloaders is a pain to maintain.
I'm not persuaded there's an avoidance of translating GraphQL. Rather, I think it's largely because of a lack of awareness of that as an option. Most or all of the material written on the subject exclusively presents execution as matter of nested resolvers and that's how pretty much all the libraries work, so I think it's natural to assume that's the only way to do it.
I will say that translating to SQL does remove a convenient arena in which to write business logic in a general purpose programming language, which generates resistance to the idea of translation once it's encountered. But, as the author says, that mixes business logic with data marshalling code anyway.
Transactions were being aggregated with thousands to 10s of thousands of SQL statements like this.
SELECT * from customer
where id = <single id>
The developers had no idea the ORM was doing this under the hood.It's trivially easy to say that if every SQL statement took 1ms to execute, that thousands of round trips can really start to tank whatever process it might be blocking.
Good thing I don't say that! What I do say is that the number of SQL calls will tend to scale with the volume of data retrieved. Limit the volume of data the user even is allowed to request and you'll naturally limit the extent of the N+1 problem.
I totally agree with the sentiment here, but disagree with the conclusion.
1. The rest of the world doesn't have facebooks data layer. Ergo, GraphQL is very hard for everyone who's not FB.
2. Turns out GraphQL is actually a really good data API. Whether it's a postgres/mongo/graph/REST data source. Because it's a great mid-point between something as flexible as SQL but as controlled as a REST API.
Here are 3 things that GraphQL is absolutely great at:
- Select a 2 fields out of a 100 attributes in a data model? GraphQL is great.
- Gradually deprecate an old field in a database and replace with a new one? GraphQL is great.
- Want a flexible way to filter/join/paginate regardless of the underlying storage layer? GraphQL is great.
Other API formats suck at this.Working with GraphQL ought to feel like you're working entirely with your database and sprinking the right bits of transform/validation/authz business logic and then the API that other teams can use is "free".
GraphQL is dying as a replacement to a REST API layer. I think GraphQL will see its second wind as a data API. Microsoft and Google announced their GraphQL data APIs recently.
GraphQL will probably only make sense when it's as close as a 1:1 map to a DB beneath it. Whether relational or NoSQL or graph.
In all other cases, the GraphQL juice is not worth the squeeze.
At the lowest level, data is stored in MySQL so yes, that's open source. Almost nothing user-facing will talk to MySQL directly because you're bypassing all the privacy, scaling, auditing, security, etc. Some legacy systems are on different MySQL instances but we're talking internal systems, not public-facing.
The in-memory graph database on top of that, which I think you're actually referring to, is called TAO [1]. AFAIK, no, it isn't open source.
All of this is very much designed for the type of data Facebook stores and how it's used (eg "12,345 people liked this" is an easy query but listing all the things you liked can be really expensive beyond the most recent likes).
[1]: https://engineering.fb.com/2013/06/25/core-infra/tao-the-pow...
Yeah I've had trouble with some devs misunderstanding this, this seems to be the source of "omg you can run arbitrary queries" (especially if they've never used GraphQL.
You can't do anything that the GraphQL schema doesn't specify - it's not open ended SQL and joins.
To be fair, it's hard to understand when virtually everyone using this term is using it wrong.
https://htmx.org/essays/how-did-rest-come-to-mean-the-opposi...
That's not necessarily contradicting the design to me. I don't know AWS but I assume you still can move data between tenants, only through some export/import system. And there may be a good a reason for it. Like you need an import/export system anyway because your tenants need it for data exchange with "tenants" that are not your customers. So you can still have both. Another reason may be a need for auditing the data movements between those tenants.
You could literally replace every part of any of the stacks he mentioned with Erlang. Python/PHP, cron, memcache, even the databases in the extreme case. It’s an older tech, too, so in his model this amounts to spending m zero innovation tokens for the entire stack.
With GraphQL you can just do the exact same thing? I do this all the time. I don't understand how you wouldn't be able to do that.
With static typing definition and OPENAPI, we can declare the response type first, and then borrow the concepts of resolver and dataloder to easily construct the response we want.
Using resolver and dataloader can iterate as fast as GQL, and after the requirement is stable, we can refactor each single endpoint on demand.
for FastAPI user, pydantic-resolve is developed for this purpose.
GraphQL is one, Redux is another.
Did Akka; thank goodness that didn't make it to production.
GraphQL: Helped in many ways. Hurt in so many too. In production.
Everything in Actors: State was everywhere. So much pain. In production.
I just use Postgres + RPCs for everything now.
There's a lot about graphql that is really cool. It just seems like the way my company uses it is to cut corners.
I'd agree that GQL is definitely one of those "gets used because it was the cool thing at the time" technologies but I still think it has a place in our toolboxes, it's definitely not the right solution for every problem.
I'm also not personally a fan of having my API queries on the frontend span multiple lines for things that with a good REST design with OpenAPI are a single method call, but all too often the calls I would need to make to the vendor's GraphQL API were exactly this: did not make use of any of GraphQL's query features, and were effectively just RPC calls.
I like the thought experiment of adding a new persisted/editable field to an entity in a web app, if you've done full-stack you know all the layers that need to be touched to accomplish this and how lame most of the work turns out to be. After doing that 20 times while iterating, any dev worth their salt starts to wonder why it sucks so bad still and how it could be made better, and some will actually try.
We just joined the CNCF, too!
With GraphQL you are doing a lot of extra work query wise than you do with REST, which is supposed to translate into various benefits. But each vendor has different implementation details that affects whether you actually receive those benefits.
This is different than REST, the benefits of REST are generally the same for every vendor because implementation details and API are extremely simple, what is different is the data structure you receive back.
In GraphQL both the data structure and the implementation details are different. GraphQL I think doesn't make sense if you have multiple data sources from different vendors, because of this increase in complexity and not being to trust how good their implementation actually is until you've gotten into it.
This gives the front-end developers lots of flexibility when initially developing new screens and components. Once the UI is ready to ship, the backend team checks to make sure that performance is acceptable (optimizing if necessary), allowlists the new query/queries, and ships to production.
But if you locally queue, and one worker gets unlucky and gets the longest tasks, then the whole cluster sits idle while this worker starts and finishes multiple tasks. If you reallocate the ones that haven’t started or have timed out, then the overall time comes down quite a bit (and in the latter case also covers workers that crash).
For development teams it could mean moving the boundary on a service or API so your team does more of the feature work than originally planned, because the other team keeps getting jammed up on bugs or other operational issues.
It doesn't work if you don't have control over the client (eg: exposing to third parties), in which case query complexity limits are easy to implement and do the job, too.
If I remember correctly it was something about Shopify discounts, which can be applied multiple times and across different modalities- percent, dollar amount, etc. and what those were called in the API, and how they were represented and to which object they were applied to.
Then once I had figured that out, then understanding how to construct the query.
But of course my problem was more from the point of view of, "I just want to get x done". As the consumer of the API I wasn't as concerned about fully understanding the entire set of abstractions and schemas.
It also means you need to be an expert in the tooling to figure it out, so just dropping in to a graphql api is so frustrating compared to plain old rest
I'm not saying the service isn't a true Scotsman, but a service that calls its API "GraphQL" but doesn't respond to introspection queries isn't really serving GraphQL.
I don't know about on-HackerNews but there's a discussion about their "all of Facebook optimizing compiler" infrastructure from when they did the site redesign in 2020: https://engineering.fb.com/2020/05/08/web/facebook-redesign/...
> perhaps not coincidentally, React introduced "server actions" as a mechanism that is very similar to [the above]
Yep - there's also the Scala framework LiftWeb (https://www.liftweb.net/), the Elixir framework Phoenix (https://www.phoenixframework.org/) and of course the system we're using right now (Arc) that do similar things. Scaling these kinds of UUID-addressed-closures is harder (because the client sessions have to be sticky unless you can serialize closures and send them across the network between servers).
But I think it comes with a lot more reluctance and skepticism. You are not likely to jump in head over heels, and even when you do give it a try I expect most farmers will do so with the attitude of "if it doesn't work at least I can always go back to the old way".
The "OMG this is amazing and will solve all of my life's problems" attitude I see in tech certainly isn't there in my experience.
Think more like marketing campaign or product design.
If you don't have fragments (in particular, if you have a single call to an swr hook at the root), then you have implicit deduplication. But then you run into the issue of it being unclear whether you can remove a given field when a subcomponent stops using it — you have to check whether any other subcomponent happens to use that.
And if you have many separate queries, you're architecting in waterfalls. But you have clarity about who uses which field.
2. No reliable way to handle queue overflow.
Combine both and you are 100% guaranteed to have an incident. (I guess it keeps devops and sysadmins employed, though.)
Rough edges sure. No reliable way to delete processed messages. Well, who’s to say they were processed? It’s a persistent queue, stuff sticks around by construction. Besides, this can be managed with tombstones and turning on compaction for that topic.
How would you want to “handle” queue overflow? You’ve either got storage space, or you don’t, this feels a bit like asking “how do I make my bounded queue unbounded”. You don’t, that’s an indicator you’re trying to hold it wrong.
The configs could be a bit easier to drive, but confusing and massive configs is pretty par for the course for Java apps ime.
The queue, which should keep a reference count for messages.
> How would you want to “handle” queue overflow?
At the producer end, of course.
> You’ve either got storage space, or you don’t
Kafka assumes you have infinite storage space. That might be okay for toy projects or for the insane architectures you see in the enterprise space, but not for a serious project.
The current version of MongoDB, imo, makes you super productive and scales without a ton of thinking. If you're working in Node.js, it's even more useful as the query language works just like a JS/JSON object so writing queries is super fast (compared to SQL where you have to spend a lot of mental cycles figuring out how to map object/array data).
I've found that denormalizing data (not even necessarily copying/duping data, but trying to centralize storage of it) when using MongoDB is the way to get the most value out of it. If you try to treat it like an RDB (which does work but can cause issues with complex queries), you'll run into headaches. If you just design stuff to be nested, though (and use the built-in APIs to query that nested data), it works incredibly well.
I think the key thing is that people using MySQL were having trouble with deep data and found MongoDB's document oriented approach much easier, but these days people are tending to start with PostgreSQL, which can handle that nicely.
(MySQL/MariaDB are far better than they used to be as well, though I find most stuff I read online doesn't take advantage of that as much as it might)
There's also probably a factor of Mongo solving pain points people had when they switched to it, and there being lots of excitement around that, where today the same people have run into the pain points of Mongo often enough that it's no longer nearly so exciting a prospect.
I wouldn't honestly be surprised if we're now at a point where people are -more- negative about Mongo than it really deserves, and I say that as somebody who viscerally hated it on sight and would still rather avoid dealing with it myself it if at all possible.
(oh and MongoDB the -company- has always done their best to be a good corporate community citizen, sponsoring all sorts of cool things as a result, and while I think the license change was a shame I -still- think they're doing their best, just in an environment where they wouldn't have a best to try to do in the first place if they didn't avoid being killed by AWS)
That sounds similar to Elastic's story. Did MongoDB go through that as well?
In the equivalent REST API you would probably have to go far far out of your way to expose users order information in a reviews API, whereas in graphql that is the default.
In a typical REST application, it is enough to ask "does this user have permission to take this action".
In graphql, the question is rather different. It is "does this user have permission to access this data irrespective of the action they are taking", and you have to both ask that question and answer it correctly for everything in your graph.
In theory, it should be just as obvious either way as your actual services are going to be REST (or similar) either way. I recognize that some people have started using it as a poor man's SQL, but that's not really what it is for.
Lmao that's just bad development, bad testing and the exact same thing can happen when using rest. "The dev wrote code and forgot to take permissions into account" happens to everyone.
And unlike rest, a properly written schema helps ensure they mostly do the right thing - even without strict permissions check, it should be obvious to anybody that they can't just write an `orders` resolver that does a `select * from orders`...
Are you proposing just to add new field to a JSON response, even though they are not needed?
That is exactly what OP is proposing and it makes total sense. More data != bad. Just ignore if you don't need it. For 99.999% of cases the bandwidth of extra data is entirely negligible.
For business cases you just want to get things done. If the server has added more data, which is obviously relevant in some regard, you can see it and might want to use it etc. With GraphQL you are completely stuck without SPECIFICALLY requesting it. That means every client needs to know about the new data and specifically request it. In theory that might sound like it makes sense, but in practice this is virtually never the case.
Give me all the data and I'll use what makes sense.
(Most) GraphQL clients are optimized for relatively small/simple objects being returned, and you typically pay a cost for every single edge (not node) returned in a response / cached in memory.
It can quickly get to the point where your project is spending more time per frame processing GraphQL responses & looking data up from the cache than you spend rendering your UI
The cure is, like you say, writing a proper resolver. This form of permissions error most frequently happens when there is not a dedicated resolver (graphql-ruby, for example, makes it trivial to make a connection without a dedicated resolver).
I don't think this is as easy of a mistake to make with a typical REST application. In no normal universe would you return orders data in a reviews API, and the mistake would be much more obvious during development since you don't have to explicitly select the data you fetch from a rest API (so you are more likely to notice the extra information).
Whereas during development in graphql, the permissions error would be hidden because you probably would not select extra data for no reason.
type Starship {
id: ID!
name: String!
}
type CaptainQuery {
captains(starshipFilter: [Starship!]): [Starship]
}
# leading to
{
captains(starshipFilter: [{name: "Alpha"},{id: "cafebabe"}]) { id }
}
which I recognize is most often fixed via variables but when the hello-world examples call it out, something has gone awry https://docs.github.com/en/graphql/guides/forming-calls-with...And even the embedded part isn't valid json without quoting the keys.
JSON is great (though not perfect) as an interchange format, but it’s decidedly not a query language.
Of course the query itself is not json, why should it be? It describes the shape of a json object, and queries are generally pretty static. But the request to the server is json, the request variables are json, the result is json, and all the json tooling can be used in the responses in our clients.
Honestly, one of the reasons I like GraphQL is the fact that underlying it all is just JSON.
writing queries is stupid easy if you use a tool like GraphIQL especially with the explorer.
With that said I still like using relay on my random react-native side projects.
I think this is a classic case of anecdotes not adding up to data.
performance was the least attractive reason for adopting React. React introduced composition as the default way of thinking about UIs to the web. You created components and used them to build more complex components. Data was immutable and flowed in one direction (parent component -> child component).
Comparing the above to ng with its dependency injection, MVC style approach to UIs, that used HTML based annotations and tags to sprinkle in functionality (`ng-if` baby) -- it was a much more simple way to build web applications.
React's style of building UIs has largely won. Vue, etc. all follow this component with composition view of the world.
> React sucked for years, with a terrible doc, a crippling webpack experience and breaking compact all the time.
Webpack has nothing to do with React. React has always had good documentation. The reason the documentation was good in the beginning was because the API surface area was tiny compared to Backbone, Ember, ng, etc..
I'm not going to go point by point here. You sound like you have a very superficial understanding of the space.
I'm going to hard pass on clicking a marketing link to your blog.
> React has always had good documentation
Tells me you rewrite the entire history.
In fact, for years, react didn't even tell in the doc you could use it without a transpiler so people had to learn a whole build chain before even getting to the hello world.
At this stage it's not "superficial understanding of the space" this kind of comment is guilty of, it's total denial.
And by the way, we have been doing components for UI way before react was a thing. jQuery could do components. Backend frameworks could do components.
As for immutable data, I've seen more small projects die from the small cuts of trying to maintain that purity that I've seen those exploiting the benefits like free time travel.
I assume you've been living HN bubble for too long.
> In fact, for years, react didn't even tell in the doc you could use it without a transpiler so people had to learn a whole build chain before even getting to the hello world.
React's original documentation site from June of 2013 (when React was first introduced):
https://web.archive.org/web/20130607085014/http://facebook.g...
> JSX is a JavaScript XML syntax transform recommended (but not required) for use with React.
It goes on to explain exactly what JSX is and how it converts to JS functions. Feel free to click around that original documentation site.
Here's the README.md from the commit at the same time:
https://github.com/facebook/react/tree/a41aa76ef36471ba07b29...
> You'll notice that we used an XML-like syntax; we call it JSX. JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. A simple transform is included with React that allows converting JSX into native JavaScript for browsers to digest.
At this point I would kindly ask you to go away.
Webpack wasn't how it started, remember gulp?
Also don't forget the switch from class components to functions, then inventing "hook" functions to reintroduce functionality that already existed in the class components.
For the past few years I've been on a team that handles a legacy system from long before React existed (internal) that just renders HTML directly, a client website that uses Backbone, and a newer client website that uses modern React. The old internal one that doesn't use any frontend frameworks has been by far the nicest to work with, and Backbone the worst.
I think that's some missing context as well - React+Redux was much better than what came immediately before it, for complex web apps. But when you're not building something like that, yeah, both are worse. It just doesn't seem like the Backbone era encouraged people to use it for everything, unlike React.
React solved a very specific issue that was a pain in Angular, which is making it easy to write small, self-contained components and attach them to a mostly static site. That people decided to use it to make entire SPAs further illustrates how much easier they found it than other solutions.
I can't think of a case where JQuery code is ever simpler than React code, even for small things. If you need to worry about the order of rendered items or moving them into different categories on a page based on input, it's much simpler in React.
I'm not sure what you mean about a poor man's SQL. Whether it's backed by micro-services via REST, or just a graphql API in a single app, the value prop for frontend<>backend communication is the same. It's not "using graphql wrong" to not have a micro service architecture.
Or are you just sending all data the client cloud possibly see over?
This sounds like a facetiously-simple answer, but it's entirely earnest. If the data properly belongs as a property of the object, return it in the object's representation. If the "data" is actually an ID of a related object, return that id (or, better yet, the URL at which to find information about that object) as a link.
Domain-Driven Design is much over-hyped, but on this they were right on the money.
("But then you have to make multiple requests to gather information which crosses the boundaries of many objects". Yes. And? Beyond a reasonable point, latency is nowhere near as important as many developers like to think it is, especially when compared with a simple and straightforward API - and if this is one of those rare cases that is on the critical path, you _can_ add a dedicated getFooWithAdditionalBars endpoint to your REST API)
XML is mostly already lost on the current generation of developers though, much less future developers. Protobuf and cousins generally do typed interchange more efficiently with less complexity.
RFC 8259 is marginally better in that it at least acknowledges these problems:
This specification allows implementations to set limits on the range
and precision of numbers accepted. Since software that implements
IEEE 754 binary64 (double precision) numbers [IEEE754] is generally
available and widely used, good interoperability can be achieved by
implementations that expect no more precision or range than these
provide, in the sense that implementations will approximate JSON
numbers within the expected precision. A JSON number such as 1E400
or 3.141592653589793238462643383279 may indicate potential
interoperability problems, since it suggests that the software that
created it expects receiving software to have greater capabilities
for numeric magnitude and precision than is widely available.
Note that when such software is used, numbers that are integers and
are in the range [-(2**53)+1, (2**53)-1] are interoperable in the
sense that implementations will agree exactly on their numeric
values.
But note how this is still not actually guaranteeing anything. What it says is that implementations can set arbitrary limits on range and precision, and then points out that de facto this often means 64-bit floating point, so you should, at the very least, not assume anything better. But even if you only assume that, the spec doesn't promise interoperability.In practice the only reliable way to handle any numbers in JSON is to use strings for them, because that way the parser will deliver them unchanged to the API client, which can then make informed (hopefully...) choices on how to parse them based on schema and other docs.
OTOH in XML without a schema everything is a string already, and in XML with a schema (which can be inline via xsi:type) you can describe valid numbers with considerable precision, e.g.: https://www.w3.org/TR/xmlschema-2/#decimal
Sure, protobuf is nice, but more limited in scope and closer to a JSON alternative than an XML alternative.
I use JSON every other day and have been for decades.
Go's XML parser straight-up emits broken XML when trying to output tags that have prefixed namespaces.
JSON won in the end mostly because it was easier to handle in JS specifically, which is what mattered for the frontend. Then other languages caught up with their own implementations, although in some cases it took a while - e.g. for .NET you had to use third-party libraries until 2019.
Browsers had XML parsers before they could handle JSON directly, and at the beginning there were complaints that JSON was harder to use for that reason. The reason why JSON won rapidly even for backend apps which never loaded it in JSON was ergonomics: every part of the XML world from the parsers to XPath/XSLT/XQuery to the rat’s nest of standards was plagued by the hairy-shirt “this is hard and should feel hard” attitude that has thankfully become less common. I saw so many people just burn out in the entire ecosystem because they got tired of unhelpful errors, pointless usability bugs around namespaces, low-quality or missing examples, and especially how common tools just stopped getting improved.
I maintain that the format would have been far more popular if all of the effort spent on standards work after the turn of the century had been suspended and the time directed to fixing things like the usability of namespaces in almost every parser, and hiring at least one person to work on libxml2 so developers could actually use features which shipped after 1999. Unfortunately it seemed like there were a ton of architects who really wanted to spend time building castles in the air and they just seemed to assume that someone else would do the boring parts of implementing it, but those people all jumped on JSON pretty quickly. I worked with a bunch of people who weren’t developers and the cycle of initial enthusiasm fading into “doesn’t this kind of suck?” with XML was depressing to watch having seen so much initial promise.
It sure is better for the backend team, but the client teams will need to have countless meetings begging to establish/change a contract and always being told it will come in the next sprint (or the one after, or in Q3).
> This leads to far more fingerpointing/inefficiency in the log run, despite whatever illusion of short-term expediency it creates.
It is true it can cause these kind of problems, but they take far, far, far less time than mundane contract agreement conversations. Although having catastrophic failures is usually pretty dire when they do happen, but there are a lot of ways of mitigating as well like good monitoring and staggered deployments.
It is a tradeoff to be sure, there is no silver bullet.
If your front-end engineers end up twiddling their thumbs (no bugs/hotfixes), perhaps there is time (and manpower) to try to design and build a "new" system that can cater to the new(er) needs.
With my single WordPress project I found that WP GraphQL ran circles around the built-in WP REST API because it didn't try to pull in the dozens of extra custom fields that I didn't need. Not like it's hard to outdo anything built-in to WP tho...
It's really not, it's not exposing your whole DB or allowing random SQL queries.
> It is far better for the Backend to provide the Frontend a contract
GraphQL does this - it's just called the GraphQL "schema". It's not your entire database schema.
And the REST API can still get hammered by the client - they could do an N + 1 query on their side. With GraphQL at least you can optimize this without adding a new endpoint.
- Each individual thing available in the request should be no less timely to handle than it would via any other api
- Combining too many things together in a single call isn't a failing of the GraphQL endpoint, it's a failing of the caller; the same way it would be if they made multiple REST calls
Do you have an example of a call to a GraphQL API that would be a problem, that wouldn't be using some other approach?
XML is so much more than hierarchical data serialization format. In a typical conversation XML generally means "JSON-compatible subset of XML" as if the other parts do not even exist. Like in the meme "Javascript vs Javascript the good parts".
XML never really took off, only the parts that make up "different flavor of JSON".
It feels like a cross between JSON and HL7 to me.
Some things were a bit weird. From memory it had big lists of records all mixed together as the implementation of references.
> Then we just come back full round trip to REST
Except that GraphQL allows the back end to define the full set of fields that are available, and the front end can ask for some subset of that. This allows for less load; both on the network and on what the back end needs to fetch data for.
From a technical perspective, GraphQL is (effectively) just a REST API that allows the front end to specify which data it wants back.
When you use the "REST" / JSON-over-HTTP pattern which was more common in 2010, changes in query patterns necessarily involve the backend team, which means they are aware of the change & have an opportunity to get ahead of any performance impact.
I've never gotten a good answer to that question, so I've never even considered GraphQL in such systems where it may have made sense.
I can see it in something big like Jira or GitHub to talk to itself, so the backend & frontend teams can use it to decouple a bit, and then if something goes wrong with the performance they can pick up the pieces together as still effectively one team. But if that crosses a team boundary the communication costs go much higher and I'd rather just go through the usual "let's add this to the API" discussions with a discrete ask rather than "the query we decided to run today is slow, but we may run anything else any time we feel like it and that has to be fast too".
How does this follow? A client team can decide to e.g. put up a cross-sell shelf on a low-traffic page by calling a REST endpoint with tons of details and you have the same problem. I don't see the difference in any of these discussions, the only thing different is the schema syntax (graphql vs. openapi)
That being said, it's a lot easier to setup caching for REST calls.
If you're providing an external API like GitHub does, then that's a different story and I agree.
Thing get more problematic when there's vertical ownership for a feature, where the UI needs just a few extra things and you end up with a REST response which is fatter and fatter, in the interest of avoiding round trips and client-side joins.
The problem with killing correct queries that take too long is that it shows up as intermittent failure that's dependent on server load and data cardinality. You might not find it in testing and it ships a bad experience to the customer before bugs are found. Whereas APIs which can't be so easily misused make it much harder to ship bugs.
Why do you think that they can't do that with GraphQL? GraphQL isn't open ended. Its a highly restricted syntax for calling nested resources. If a resource is expensive simply don't nest it and make it a top level field and it is the same as REST?
Lots of nested resources are by default efficiently served by GraphQL because they are mostly returning single object foreign keys. Something that would take extra calls with REST.
GraphQL can have the same restrictions and performance guarantees as REST but the later is not necessarily true because in REST there is no standard way to define nested resource access.
GraphQL only exposes what you ask it to. There are plenty of pagination plugins for GraphQL frameworks just as there are plugins to REST framework.
GraphQL can be restrictive as REST if you want it to be.
The point is GraphQL can be "as restrictive" as REST, but if you want to enable more efficient queries by knowing all the data that the frontend is requesting, you can. But the opposite isn't true of REST. With REST if you want more advanced functionality like that you have to define your own specification.
Yeah, the client can't change the query if you don't let it specify a query, this is trivially true, but the developer can go break an API endpoint with the exact same result while trying to achieve the exact same business outcome.
If, at page load, I’m making 100 HTTP requests to fetch 100 assets then as a client side developer I’m going to know that’s bad practise and that we really ought to have some kind of multi-get endpoint. With GraphQL that gets muddy, from the client side I’m not really sure if what I’m writing is going to be a massive performance drag or not.
Yes, so the cost benefit here is not in favor of GraphQL. If both technologies ultimately suffer from the same issues (what to do about unpredictable clients), but one is far more complex to implement and use (GraphQL), then there's a clear winner. Spoiler, its not GraphQL.
Page specific endpoints, I would argue, can do 99% of what GraphQL was trying to do. If you want to use it as some sort of template language for constructing page specific endpoints, that could be useful (the same way xml schema is useful for specifying complex xml documents).
But you can optimize a page specific endpoint, and do it with REST-style endpoint to boot.
Having a bunch of "simple" calls and optimizing for the "complex" ones that you need using metrics/analysis is what you should be doing, not creating a complex API that is far harder to break down into "simple" cases.
The engineering work involved shifts from building individual endpoints to building the endpoint factory. This shift may or may not be worth the trade off, but there are definite advantages, especially from the perspective of whomever is building the client. And once you factor in the ease at which you can introduce partial streaming with defer and streamable (granted they’re still WIP spec-wise), the experience can be pretty sublime.
I think that’s what’s really pointing out the root cause issues here, it’s not purely GraphQL’s problem, it’s the problems inherent to distributed systems.
But let's say you have a timeout, and they have a retry, then suddenly, your server is now spammed by all the clients retry again and again a query that worked a week ago, but today is too heavy because of a tiny change nobody noticed.
And even if it's not the case, you can now break the client at any time because they decide to use a feature you gave them, but that you actually can't deal with right now.
I always am happy when I get an elegant query working. Often however I just find I wasted time looking for a clean 1 query solution when iteration by caller was the only solution.
Surely that is always the case, if the client is composing multiple REST requests, or if there’s one RPC method per client page, or with any other conceivable data loading scheme.
What ends up happening is the clients doing work arounds to backend problems which creates even more technical debt
The other extreme end example is to expose by default the entire data model (PostGraphile) and then getting lost in the customisation and authorisation.
This? Yeah, that seems neat, for command/batch queuing.
I'd be curious how it compares to e.g. rest apis returning refs to e.g. webrtc streams or tcp/udp ones for non-browser. I presume the main advantage would be client side.
It takes a lot of work to actually ensure all possible combinations of graphql params hit exactly what you want in the backend, and it's easy to mess with it in the frontend.
Sure, you can disable it, but the fact that it is opt-out to begin with - i.e. that by default the parser will try to creatively interpret any string it sees in JSON input and convert in a locale-specific manner that also quietly loses data - is, frankly, insane through and through. I've personally run into this issue many times in existing code - it usually happens when people first start using the library and just never run into any inputs that would trigger this behavior while testing. Then once that code is shipped, someone somewhere just happens to have the data that triggers it.
And if you look at the comments to that issue, there are numerous mentions from other GitHub repos due to bugs it caused for them, including some Microsoft projects.
The cherry on that cake was author's response indicating that he doesn't even understand why this design is problematic in the first place: "I like what it does, I have no plans to change it, and I would do it again if given the chance." I wouldn't trust any parser written with this kind of attitude.
A hand-coded REST endpoint will give you a bunch of predefined options for filtering, sorting etc, and the dev who implements it will generally assume that all of those can be used, and write the backing query (and create indices) accordingly.
Flexibility within the constraints of what the back end can safely support.
To me, the "whole point" of GraphQL is to be able to have the client ask for only the data they need, rather than have a REST API that returns _everything_ and letting the front end throw away what they don't need (which incurs more load).
If you can't support returning certain configurations of data, then... don't.
The graphql usage I'm used to works more or less the same as REST. You control the schema and the implementation, you control exactly how much data store access is allowed, etc. It's just like REST except the schema syntax is different.
The main advantage of GraphQL IMO is the nice introspection tools that frontend devs can use, i.e. GraphiQL and run queries from that UI. It's like going shopping in a nice supermarket.
For Postgraphile, it leans more heavily on the database, which I prefer. Set up some row-level access policies along with table-level grant/revoke, and security tends to bubble up. There's no getting past a UI or middleware bug to get the data when the database itself is denying access to records. Pretty simple to unit test, and much more resistant to data leakage when the one-off automation script doesn't know the rules.
I also love that the table and column comments bubble up automatically as GraphiQL resolver documentation.
Agreed about the introspection tools. I can send a GraphiQL URL to most junior devs with little to no SQL experience, and they'll get data to their UI with less drama than with Swagger interfaces IMO. (Though Swagger tends to be pretty easy too compared to the bad old days.)
> I can send a GraphiQL URL to most junior devs with little to no SQL experience, and they'll get data to their UI with less drama
But that's like giving direct (read) database access to someone that was taught the syntax of SQL but not the performance implications of the different types of queries. Sure, they can get the data they want; but the production server may fall over when someone hits the front end in a new way. Which is, I think, what a lot of people are talking about when they talk about GraphQL having load issues based on the front end changing their call.
I think that's the part where I have a disconnect. To me, both REST and GraphQL likely need to hit the database to get their data, and I would be writing the code that does that. Having the front end's call directly translated to database queries seems insane. The same would be true if you wrote a REST API that hit the database directly and took table/field names from query parameters; only... we don't do that because it would be stupid.
No because if you dont do that you have to involve more engineers anyways to build the REST endpoints and keep modifying the rest endpoints.
GraphQL is also default restrictive (i.e. exposes nothing). You don't need to add engineers to make it restrictive.
In Startups typically:
-> Frontend changes most frequently
-> Backend "utility functions " changes less
-> Data model changes the least
Without Graphql your "backend" ends up needing to have a lot of work and changes because it is constantly needing to be updated to the needs of the most frequent changes happening on the frontend.With GraphQL the only time you need to update the backend is when those "utility" functions change (i.e. 3rd party api calls, etc) or the data model changes.
So you end up needing substantially less backend engineers.
The vast majority of projects don't gain anything from this flexibility, because you don't have suddenly a 1000 of farmvilles copy cat that need their own little queries. You just have bob that need an order by.
This is akin to saying that "directly exposing the database is easier, you only have to change things if the data changes".
And yes this is true, but when the data changes, or the environment changes, the paradigm falls apart a bit, no? Which is what the backend code was for, insulation from that.
> In Startups typically:
Yes, so for a short lived, non-scaled application its far easier to do it one way, and maybe that's fine for most small apps (that will never scale far). I suspect a lot of the push back comes from larger, less nimble, more backwards-compat focused organizations/apps.
You get something more complex, more expensive to maintain, consuming more resources, and configure it to basically be REST with extra steps.
Idk. Strawberry GQL and most GQL libraries are maybe equally as complex as the REST libraries for the same language. Strawberry and FastAPI I would say are equal in complexity and configuration.
It would be hard for me to say GQL is more expensive or consumes more resources. Opposite of the purpose and most uses of GQL.
And you can both put queries on an allow list, control max query depth, and/or throttle on query cost.
All of which are features which give you some way to respond to the performance issues you avoid by planning your API up-front.
There are no free lunches, especially with regard to security and sanity checks.
Far from it actually. I am saying that in practice the data and queries that you perform on your Database actually tend to stabilize and you add less and less as time goes on.
By Allowing the frontend to select what combination of these pre-approved queries that you already approved it can use, you have to do less and less backend work when compared to REST where you have to do backend work for every query combination you want to serve.
> maybe that's fine for most small apps (that will never scale far).
I mean saying GQL doesn't scale for big apps is over looking one of the largest Corporate Software Orgs (FB) created and use it in production purposefully for managing large software APIs.
Sure, so you are just filtering raw database access then. That doesn't make it any different - and, you still need to approve and filter these queries, so what exactly have you saved? I.e. either the front end engineers can change these filters, or not, so it amounts to the same thing in the case they can.
> I mean saying GQL doesn't scale for big apps is over looking one of the largest Corporate Software Orgs (FB) created and use it in production purposefully for managing large software APIs.
That's not a great argument, though, saying a large company with many resources is capable of supporting something does not make it a sustainable technical decision. They likely also have a very specific work structure they use to make it for them.
In fact thats a strong reason not to use it, if it requires enterprise level resources to use it effectively. There is a big difference between technologies that scale to enterprise and technologies that require enterprise...
It still comes down to, if you can achieve 99% of the same thing with autogenerated REST apis and a couple page specific apis, what, exactly, is worth the considerable increase in complexity for that remaining 1%? Making things regularly more complex is a hallmark of failed, bad technologies, and I suspect GraphQL will see the dustbin like SOAP did...
> It still comes down to, if you can achieve 99% of the same thing with autogenerated REST apis and a couple page specific apis
Because you can get 100% by autogenerating GQL APIs and 0 page specific apis.
No, I never said that. You are the one that brought FB into the equation.
Just because it can be used for something does not mean that it should.
I said that that approach doesn't scale well, especially for frequent data/model changes. For small apps, where as you say, you have few data changes, by all means embed your database as closely as possible to you end user code.
Sqlite inside a c app or electron, e.g. No need for any API at all! Just raw query access.
Its nice GQL to generate stuff for small non-changing web apps, I'm sure. But once you get into more performance oriented, data-migration-style stuff, if there's not good support for changing the data and reacting to the environment, then adding complexity (GQL) to an already complex situation is a Bad Idea.
You never said what this 1% was, autogeneration is not a bonus when you already have to manually filter and route things. The simpler solution gets you there as well, with less fuss.
You think you don't have page specific apis, but if you are doing the manual filtering, then you still have them, you are just "hiding" them inside another language, that doesn't have a clear benefit? At least you can't say what it is, without going in circles, another sign GQL is probably ultimately a garbage technology...
The idea that resources and the underlying data needs to map 1-1 is wrong.
The GP's idea that a frontend developer would send a ticket to somebody so they can get all the data they need... it's just crazy.
On the other extreme, we have the HTTP 1.0 developers saying something like "networks are plenty of fast, we can waste a bit of it with legible protocols that are easier to make correct", while the HTTP 2.0 ones are all in "we must cram information into every single bit!"
Every place you look, things are completely bananas.
For me, what's crazy is that there are "web" developers who can't just add the endpoint they need while working on a frontend feature, or "web" developers who can't just add an element or a page for testing the backend endpoint.
What ever happened to full-stack developers? The "frontend" and "backend" developer split is so incredibly inefficient that it's really jarring—you take something that should take 2 hours and magically, through tickets, delegation, and waiting for results (then repeat that for debugging, who knows how many times!), make it into a 2-3 day task.
I once reproduced (black-box style!) a two-week effort by a three-man team in six hours of work simply because I had PyCharm and IDEA opened side-by-side and could write code on both sides at the same time.
If someone has a good explanation for why the full-stacks that were once the norm went almost extinct, I'd be happy to give it a read!
There is no easy or simple or final solution. The solution is to do the hard work of software engineering and catch this stuff at code review time or to plan and do refactoring later when you realize something needs normalization. I wish developers would just accept that software engineering is hard and do the hard work necessary.
There's that whole "the best software engineer is lazy because he will automate stuff", but that does not give anyone a license to automate stuff in an unmaintainable way. Automating stuff is hard and there is no easy way out.
Even though we use GQL here, we still have a B4F, so it's browser -> B4F -> GQL -> Database.
The tooling we use make it trivial so it doesn't add any development overhead (often reduces it. No CORS bullshit for one), and our app goes ZOOOOOOM.
"We need a http API endpoint that gives you all the data for one page. And also be able to reuse parts of it for other pages." Yeah bro, this is GraphQL.
Screen-specific REST endpoints will make their way as a default in to a JS-based framework in 2025 and people will pretend like this is some breakthrough advancement.
Hardly gross. It is what it is and it’s universal across the domain. I bet Windows has internal APIs or even external ones that were created just for one page/widget/dialog of one app. It’s the nature of things at times.
For example, a lot of times people build out nice normalized table structures for online transactional apps. The UI/UX is pretty straight forward because end users typically only CRUD an object maybe a couple nested objects at a time. The API's are straight forward as well, likely following single responsibility principles, etc. Then comes along requirements to build UI's for analytics and/or reporting types of things where nearly the entire schema is needed depending on what the end user wants to do. Its the wrong data model for doing those types of things. What should be done is ETL the data from the OLTP schema into a data warehouse style schema where data is de-normalized so that you can build reporting, etc.
With REST, though, that pain is visible to both sides. Frontend engineers generally don't want to make N+1 REST calls in a tight loop; it's a performance problem that they see and that is very visible in their Dev Tools. Backend engineers with good telemetry may not know why they get the bursts of N+1 calls that they see without asking the Frontend or digging into Frontend code, but they can still see the burstiness of the calls and have some idea that something could be optimized, that something is maybe too chatty.
There are multiple ways with REST to handle things: pagination, "transclusions", hyperlinks, and more. Certainly "single page endpoints" is a way as well, no matter how gross it is from REST theory, it's still a pragmatic solution for many in practice.
REST certainly can please everyone, given pragmatic compromises, even if it isn't very clear or standard.
Single page endpoints is exactly what you want if you have more than 5 engineers in your company anyways.
It ensures that the endpoints are maintainable and future-proof when people are working on different features.
How does GQL prohibit this? It encourages it by focusing on 1 stable API for everyone instead of a custom API endpoint for each case.
But you still need all of the various single page REST/RPC endpoints to make use of GraphQL as it is intended. Some developers out there skip the REST/RPC part, making GraphQL their entire service, violating its principles.
If it works it works, but it does not come tradeoff free.
That's why GraphQL examples usually focus on querying data from users and not how you are going to manage 10 different views of the same data.
I also recall, we had similar N+1 query problems in the REST API endpoints irrespective of hydrating the returned resources.
The biggest benefit of GraphQL I can see from a user perspective is that it lowers total latency especially on mobile with fewer round trips.
there's lots of other benefits for GQL: multiple queries per request, mutation/query separation, typed errors, subscriptions support.
GET /myresource?extra=foo,bar
sure you over fetch a bit if you have multiple accessors.
But agreed, if you have highly nested data especially when accessed with multiple different query purposes then REST might not be the best fit.
I think GraphQL has been positioned as a general purpose tool and for that I am with the author, REST is a better go-to for most usecases.
Any more levels and you have now reinvented GraphQL
Sure, but reinventing the wheel can be good, particularly when the existing wheel technology is oblong, lumpy and constructed of stone and cheese.
I’m just bitter than GraphQL endpoints return 200 on errors. If you’re returning 200 on errors, then you’re not really doing HTTP; you’re just using HTTP as a substrate for some other protocol, in which case you might as well just open a port and serve that protocol directly and not pretend to be HTTP.
> With internal REST for companies I have seen so many single page specific endpoints. Gross.
As someone pointed out in reply to another comment, GraphQL is "a technological solution to an organizational problem." If that problem manifests as abuse of REST endpoints, you can disguise it with GraphQL, until one day you find out your API calls are slow for more obscure, harder to debug reasons.
That's an established pattern (backend for frontend). Like all patterns there are trade-offs and considerations to make, but it's certainly not a priori "gross".
https://learn.microsoft.com/en-us/azure/architecture/pattern...
And, resources with an index option obviously should have a db index or unique index.
The challenges with GraphQL are that it makes it too easy to DoS services, leak internal data, break referential integrity, and there were a great deal of tools, infrastructure, and monitoring systems already available for REST (and gRPC to a degree).
Company standards for REST and coding style can and should be set in the diff review pipeline. Another facet is setting standards to minimize duplication of effort or exposing a greater attack surface.
When you realize that sometimes your REST model may be a view-model that maps to a different storage model optimized for online-transaction-processing, neither of which map to your internal domain model directly (there are adapters for that) _then_ you get somewhere ... but of course you then have to fight off the `transformToRestModel(transformToDomainModel(retrieveDbModel(theId)))` when the three models happily coincide for a time.
I think this explains about three quarters of all engineering problems I've seen in corporate context, give or take.
What people are excited about is that the frontend can request all the data it needs at once and the backend can efficiently serve it. Something not possible with REST without reimplementing something similar to GraphQL.
An engineer had to spend time to make that specific API for that page instead of the frontend consumer using what was already defined and get all the resources with one call and 0 backend engineer needed for that new page.
And that's assuming it's a new endpoint; if there's an existing endpoint that does almost what's necessary, they may need to check in with that team about what modifications to the endpoint would be acceptable, etc.
Single-page endpoints aren't great, but often times they're acceptable because they end up being a half-day task instead of a week-long slog.
In graphql land you'd be doing multiple SQL queries, "joining" in the API layer, and spending 50ms per API call.
We use a schema first design where I am at and if a frontend person needs a new endpoint because the resource-only endpoints aren’t enough then they submit a pull request to the schema repo with a design for their endpoint they need. It gets approved and boilerplate is auto generated. Yes you have to wait longer, but 90% of the time (for our software) the resource endpoints work great.
It's better to think about optimizing of creation specialized APIs.
And GraphQL isn't free either; you need to actually implement that. It pervades your entire stack, too – it's not something you can just "put on top of it".
I think that in many cases, perhaps even most, GraphQL is a "spend 8 hours to automate a half hour task" kind of affair. Are there cases where that's not the case? Probably. Maybe your specific use case is one of them. But for the general case? I'm entirely unconvinced.
Browser does not allow to access any ports with any protocols.
Often intermediate software gets in the way as well. For example with Kubernetes it's trivial to expose HTTP service using Ingress and it's not trivial to expose other protocols.
Another HTTP plus is that it's trivially secured by TLS and every developer knows API for that. Using TLS for your own protocol or QUIC is absolutely not trivial and probably more like arcane knowledge.
I'm not sure where this narrative comes from that GraphQL immediately means that the frontend time will have no idea what they are doing and will induce load on the system.
95% of my nested graphql fields are based on foreign key indexes so its almost no additional load to the system (only 1 query per "level" of GraphQL) to query the nested objects.
I restrict GraphQL to 5 levels and now I have 5 queries per API call instead of 5 Queries over 5 API calls.
The backend team exposes the fields that they know are efficient to query. They can restrict the depth of the GraphQL, number of fields, etc.
Look at OData download stats on Pypi it had 2 downlaods the last day. Graphql-core for python? 624,201. that is not even on the same planet.
If you don't use GQL and want a system of querying nested data you will be using a less used protocol that is analogous to GQL so you might as well use the standard.
To trade anecdotes for anecdotes: On Nuget, the Microsoft.Data.OData package marked deprecated and marked with CVEs for critical bugs still has an average of 36.3K per day downloads. (Its successors combine for about double that.) The top GraphQL library (of the same name, unadorned) still only has 9.3K per day downloads. In .NET if you want a system of querying nested data (that is also "REST compatible"), why would you use a less used protocol like GraphQL?
Why waste any time?
> And GraphQL isn't free either; you need to actually implement that
Rest isn't free. You have to actually implement also that and end up with a more limited API.
GraphQL libs in Python are equally as complex as the FastAPI etc..
> GraphQL libs in Python are equally as complex as the FastAPI etc.
You need to account for the fact that anything can query anything, whereas a more traditional REST-type API will have much more limited codepaths.
This starts with just basic database maintenance and indexing, which in many case will be significantly more complex, to all sorts of other problems. This article already enumerates them so I'm not going to repeat them here.
You can't just handwave all of that away with "oh there's a library you can use".
If you think all of that is worth it then that's fine. As with many things it's a trade-off, and a bit of a judgement call too. But please, don't pretend this complexity doesn't exist, and that the trade-off doesn't exist.
That is how REST works but is the opposite of the way GQL works.
You don't pile into existing defintions but extend the current definitions out. A team needing new data doesn't affect the consumption of other teams. which is not the case of REST where if one team needs to change a REST endpoint to return different shape of data, they have to verify the new shape with other teams.
With GQL though, good luck retracing who owns what field and what does it affect if you change the definition of what it returns, especially that you you are not even using it on the same language.
Bonus points here if you are managing something outside of your control like a mobile app.
Also, Its about 1 line to set up CI to extract all GQL queries from a typescript project and do static analysis to check against the schema.
But again you only care if someone deletes a field, and even if you have to delete it, at least the GQL schema has built in annotations for deprecation, something not in REST.
I used to be in charge of the stored procedures that served as the API to a shared database system used by many teams. (So, not exactly the same thing, but I'd argue that the sprocs vs ORM debate isn't entirely dissimilar from the REST/RPC vs GraphQL debate.) My turnaround time for getting database API changes into staging for application teams to play with was typically less than one work day. But that happened because I had a lot of latitude to just get things done, because the company valued rapid delivery, and therefore made sure we had what we needed to deliver things rapidly, both from a technical and a business process perspective. This was in a very highly regulated industry where every change required paperwork that would be audited by regulators, too.
I've also worked at places where this sort of thing took ages. Typically the worst places for work backing up were organizations that used Scrum, because the whole "sprints" thing meant that the _minimum_ time to get something from another team was about 1.5 times the sprint duration. And even then you could only manage that if you could deliver a request that already met all of that particular team's requirements for being able to point it, and could convince their Product Owner that it was a higher priority than whatever their pet project is this quarter, and the stars align so that you perfectly time the submission of your request with respect to that team's Scrum process's frame rule.
The thing I want to point out here is that absolutely none of that bullshit was ever the API technology's fault.
Most of our frontend features now don't have backend changes and we were able to increase the ratio of frontend to backend devs.
Making a good API on a large system with many clients is always difficult. GraphQL makes it easier in theory, but if you have average level devs working on it, they’ll make a bigger mess than if they use simple REST. The latter will still be complex, but at least it’s easier to have observability.
I started my career as a full-stack developer, but went all-in on frontend because I felt I was spreading myself too thin. At one point I found that I could choose to be almost good enough at doing two different things or extremely good at one thing. I chose the latter option.
Modern browser apps are complex beasts, at least if you want to do them right. You obviously have to worry about all the technical bits --- HTML, CSS, JavaScript, your view library of choice, platform APIs like <canvas> and WebAudio, cross browser testing, bundle sizes, performance optimizations, techniques like optimistic rendering, all that good stuff.
On top of that, you also need to work closely with designers to make sure they know the features and limitations of the platform(s) they're designing for. More often than not, you end up being a sort of bridge between the backend devs, designers, and product managers.
A lot of times you end up doing design too, whether you like it or not. I've learned a lot about UI/UX design just because I often have to fill in the gaps where a designer forgot to include a certain error state, or didn't test their design on tablet screens, or didn't account for cases where a certain API might not be available.
I tried for many years to learn as much as I could about Django as well as React and friends. But it eventually got too much. I found that I wasn't able to keep up with both ecosystems, and I was producing code that wasn't very good. I could certainly build things quickly because I was familiar with all parts of the stack, but it came at the cost of code quality, security, stability, and robustness. I eventually decided to hang up my backend developer hat and focus exclusively on what goes on inside the browser (which can be a lot by itself these days!)
It's probably possible for a single individual to build a high-quality server-rendered MPA with some forms without making a mess of it. But that says more about how good Rails/Django/Laravel are than about the capabilities of any single individual. I don't think a single person could build a product like Linear end-to-end without cutting corners.
Any query you were going to build and serve with Rest can be made with these two methods or even a raw dataloader and manual SQL string.
In practice with REST the frontend engineer didn't want to wait and tried to use the existing REST endpoints, did N+1 API HTTPS calls and then joined them client side in javascript.
1 graphql query maybe. But that translated to a dozen SQL queries.
> In practice with REST the frontend engineer didn't want to wait and tried to use the existing REST endpoints, did N+1 API HTTPS calls and then joined them client side in javascript.
The point you're missing is that for 1 graphql query the API did N+1 SQL queries, and then also joined them in JavaScript.
In the REST case the front end can switch to the efficient custom endpoint when it is implemented. In the graphql case it will never get any faster because the API has to stay generic.
For one, clients (mobile, desktop) are drastically different with all sorts of downstream implications:
- Differing screen size requiring responsive design
- Internet speeds magnitudes different
- Intermittent internet
- Uneven feature support due to different versions of browsers
- Everything needs to be JS at the end of the day
Desktop apps generally don’t have to worry about any of these issues.
Also, desktop GUI frameworks are typically either fragmented (one per OS) or don’t look OS-native.
Cutting corners is a feature. I bet the Linear team is as pained as any, internally, at the tradeoffs they're making.
There is no way to know "what to get right" without going through it. So for 80% of the dev cycle the job is to cut corners to get to the 80/20, rinse and repeat forever.
This isn't against excellence and the dream of a beautiful product experience as your reply seems to convey.
But yes, that break-down of the problem is insane. People artificially split an atomic problem in two, and go create all of that extra craziness to try to solve the communication problem they made.
And then people go and push UX and UI tasks into the frontend developer, and ops tasks on the backend since them are there... What is insane again, because those are really incompatible tasks that can't be done with the same mindset.
And since it's standard, backend tools won't support the frontend and the other way around. So the insanity gets frozen on our tooling.
I wrote some front-end stuff back in the days but I've lost track of whatever is happening these days. jQuery to append some stuff took five minutes to learn, but learning react hooks takes a determined effort.
Likewise, adding a field to a graphql type is simple, but doing it with authorization, controlling n+1s, adding tests etc.. requires front-end folks to actually invest time in learning whatever back-end they're dealing with this time.
Everything is just a lot more complicated these days, and if you've been around for a while you may not be excited anymore by the churn, but rather fed up.
At my startup there are 7 devs who can all do tickets across the stack and as we grow I think it would be good if we could resist the pressure to silo and specialize
It really is. Regrettably, I've drifted away from it in large part because of client requirements for more "modern" and "maintainable" solutions (e.g. Python or Node; I'll take Python every time, thanks). Django comes very close in terms of productivity (and is better in some ways: auth, admin, etc.) but the Rails CLI, generators and community (not sure if this is still relevant) give it the edge.
The "recent" (last 10+ years) movement towards "lightweight" libraries (instead of frameworks) that require you to either reinvent the wheel, copy-and-paste or use some random "getting-started" template every time you start a new project is disheartening. As others have said above, I think it's partially resume-driven-development and people wanting to tinker (both of which I do appreciate).
Something which continues to surprise me is that there hasn't really been a "modern" successor to Rails. Granted, I haven't kept pace with developments in the Node/TypeScript world but, last time I looked, Sails was on the right track but wasn't very actively developed and I was shot down (in favor of Express spaghetti) when I suggested it. There's also a smattering of Rust web frameworks but none that quite fit the bill and come with all of the batteries and opinions included. I keep saying I'm going to do a Summer of Code project which attempts this but ... life.
> The database will already have its own API
Where is this API coming from? You have to build it. I'm saying you should make those APIs graphql apis though a language framework and not REST apis because GQL consuming GQL is much better than GQL consuming REST.
Yeah sure you can make it work with anything if you spend the extra effort but the ownership really isn't as defined as in REST.
Is there code which have fuzzy or no ownership? Are there changes which affect other teams? Suddenly those became much harder questions to answer.
Its much easier to trace and debug what teams are using GQL fields than REST. What if one team is piggy backing on another teams exising rest endpoint and you dont know? same problem that would require some analysis of all code calling and endpoint to determine if a field is safe to delete. GQL makes this much simpler than REST.
I know there's some diverging opinions here but there's one which sounds definitely easier than the other.
As for deletes, I work in a company with a good hundred devs so that happens weekly at least.
As far as looking OS-native, this is (unfortunately) increasingly less relevant as OSes themselves drop desktop UX consistency even internally. But that aside, Qt is still around and is a very mature framework for "near native" UI, and then there's Avalonia and others. Even Gtk is surprisingly decent on Windows these days. Although I'm not sure what this all has to do with the original subject, since web apps most certainly don't look native anywhere.
"That would be one way to implement the system in a DB-centric way. However we believe that intermediate application code is pretty critical to any GraphQL implementation." [1]
"GraphQL is a client-server dance that needs server-side capabilities, not just CRUD semantics." [2]
GQL implementations don't map to the database but to application code.