Seems this particular twitterer made the mistake of trying to implement their own GraphQL server from the ground up. Never do that! There are ready-made servers with neat resolver patterns which allow you to respond to queries with well defined entities while fetching their fields from any source.
That said, never do that, either! There are ready-made GraphQL adapters available for pretty much any database, and there are some very promising ”GraphQL-native” databases out there too!
And then there is Prisma, which is a one-stop shop for all your app’s GraphQL needs, whatever the database.
Prisma is also an interesting case as it used to be queried via GraphQL but now they use their own query language. It’s still quite useful to build GraphQL based APIs though.
I don’t doubt that at all! However, I do not consider domain experts authority figures, however omniscient or infallible they may present. On the contrary, given how easily expertise distorts perception of knowledge, I find it prudent to avoid putting expert opinions on a pedestal, and to provide complementary views where possible.
The ready made servers often don’t handle authorization well or at all. Prisma is just an orm. This reads like somebody who hasn’t built a lot of prod stuff.
Since I first used GraphQL, my opinion has been: I like it for admin applications where the client can safely be trusted to tell me exactly what they want, and as long as I authenticate them, they can have it. For everything else, it's more of a headache than it's worth, and I'd take REST any day.
I've put a couple GraphQL services into production and have similar thoughts.
What suprised me most were the range of views from colleagues when they needed to integrate into one of their products. Some people were happy to work with something new, while others didn't appreciate the tax involved with the learning curve.
That said, I published an app that auto-provisions a CRUD service in GraphQL. So while I may not use it for most apps, I use this for general data-access.
Interesting that GraphQL consumers would see it as excessively taxing. Did you mention that GraphQL APIs can be queried with plain HTTP requests without any specific GraphQL client?
Indeed. Thats actually how my team's FE engineers called our API.
But once other teams started integrating -- we heard all kinds of feedback.
My thoughts afterward were simply that people under the time pressure to push features daily had different appetites for any friction in their workflow.
We considered the feedback from the larger team and intentionally added support for both REST & GraphQL in our next app. We wanted to support anyone that wanted some exposure to it without forcing anyone. And that had much better feedback from consumers.
True, a query is needed, but that is pretty straightforward and crucially, there are schema-aware editors that just plug in to the endpoint. Boom, autocomplete for fields and queries, and syntax validation out of the box. Indispensable piece of any GraphQL backend stack.
Besides, any sane developer will build an abstraction on top of the fetch request.
The difference to any other JSON reply is minimal.
There's an interesting tension here. On one hand, GraphQL is versatile and can simplify frontend data handling code. On the other, as schema and data sizes grow, query expressiveness is limited and performance can be quite difficult to maintain.
I've put GraphQL in front of TB-scale data sources with X00,000 tables, and it was clear that (a) GraphQL wasn't designed for anything that big, and (b) if we could get it there, it would be transformational.
This is why I built Trustfall[0]: a system that keeps the elegant GraphQL syntax, and tweaks the semantics to ensure great performance and better expressiveness: left joins / recursion / aggregations / arbitrary filters etc. Trustfall flips the proposition around: acknowledge we're wrapping a database around every data source (API server / database / filesystem / ML etc.) and make it the best possible database it could be.
I also recently used it to build cargo-semver-checks[1], a semver linter for Rust crates where each semver rule is implemented as a query using Trustfall's GraphQL + custom directives syntax.
I've been using graphql on the FE and BE for about 2 years now, and used REST for about 10 years before that. I really like the apollo client when using React, it's a great fit and let's me avoid the mental complexity of data stores like Redux etc.
On the BE it's not great, harder to reason about than REST and harder to manage. It's also harder to monitor than traditional REST, since REST makes use of a full range of http header codes (the graphql server we used only used http header 200 by default, we have modified this).
What I recently learned is that the apollo client has support for REST APIs, this is a path that seems interesting to me. We've also been looking at FE libraries for REST that have similar interfaces to the apollo client, if you have suggestions please let me know.
We're happy users of react-query[1]. Its stale-while-revalidate approach makes Redux and Co. unneccessary for most use-cases.
If you have an OpenAPI spec of your REST API you can auto-generate a react-query based frontend client with Orval[2]. Works pretty well, but probably takes a bit more time to set up.
Thank you, react-query is one of the solutions we were looking into, glad to hear there are happy users of it.
One thing I like about the apollo client is that it handles a lot of the cache invalidation for you, where as react-query it seems to be a bit more of a manual process, how are you and your team handling cache invalidation?
react-query indeed doesn't automatically take care of this. We manually invalidate its caches (based on the query key, so you only ever invalidate what has changed) after a mutation happens. It's not as bad as it sounds because most of the time it's just one line of code.
Does Redwoodjs’ architecture solve most of this? Seems like most of the challenges are about over trusting the client and Redwood has some patterns to separate. I’ve got close to zero xp with Graphql and redwood fwiw
Graphql is great when you are in node/react world. Other language support is not that great. Every language need apollo-server, Apollo-client like library
The C# ecosystem has HotChocolate (server-side) and StrawberryShake (client-side). I've been using it for a year or so and it's been a pleasure to work with.
I've actually been pleasantly surprised building a GraphQL API in PHP (which I just assumed would be a nightmare), Lighthouse is pretty strong for this.
GraphQL solves the rough edges of REST that didn’t exist in RPC. Just go back to RPC. Still works great, and now we have modern frameworks like gRPC that make
it a joy to use.
I find this to be an odd and not useful characterization.
Also, the idea that we can just 'go back' is silly.
> GraphQL solves the rough edges of REST that didn’t exist in RPC. Just go back to RPC. Still works great, and now we have modern frameworks like gRPC that make it a joy to use.
Graphql slows you down and enforces types. Both can be good or bad.
I suspect that front-end people like it because it requires less thinking on their part. A GraphQL call can replace a bunch of REST calls, and they don't have to deal with error handling and networking which in the front-end can be really difficult. Pushing that to the back-end makes their lives easier.
I've found that on the back-end GraphQL is more work than REST, because there's a bunch of extra crap you have to do to essentially do the same thing as REST.
And there's a bunch of stuff that's deliberately undefined, like "what do you do if there's a partial failure of your calls?"
At the risk of sounding like an evangelist: if it’s slowing you down, you may be doing it wrong.
If you are hand-crafting interdependent query logic to resolve GraphQL queries from multiple sources and doing that at scale, you may want to look at db adapters and the federation pattern.
Also, GraphQL absolutely still requires error handling in the frontend, and many clients actually provide great facilities for error handling: retrying failed requests, refreshing auth tokens transparently on received auth errors, network state detection, offline functionalities, etc.
I’ve found code generation tools extremely helpful for large-ish graphql backends and resolve many of the ‘complexity’ issues if employed correctly.
Of course, code generation has its own particular set of gotchas and problems (for example, you really don’t want to expose the full functionality of, say, the Prisma api to the world)
37 comments
[ 3.8 ms ] story [ 80.0 ms ] threadSeems this particular twitterer made the mistake of trying to implement their own GraphQL server from the ground up. Never do that! There are ready-made servers with neat resolver patterns which allow you to respond to queries with well defined entities while fetching their fields from any source.
That said, never do that, either! There are ready-made GraphQL adapters available for pretty much any database, and there are some very promising ”GraphQL-native” databases out there too!
And then there is Prisma, which is a one-stop shop for all your app’s GraphQL needs, whatever the database.
I’ve looked a couple times and didn’t find anything.
DGS isn't a terrible place to start, if you're already in the Spring ecosystem https://github.com/Netflix/dgs-framework#readme
There's an "awesome" list in the graphql-java org, too: https://github.com/graphql-java/awesome-graphql-java#readme
https://www.apollographql.com/docs/federation/supported-subg...
I've put a couple GraphQL services into production and have similar thoughts.
What suprised me most were the range of views from colleagues when they needed to integrate into one of their products. Some people were happy to work with something new, while others didn't appreciate the tax involved with the learning curve.
That said, I published an app that auto-provisions a CRUD service in GraphQL. So while I may not use it for most apps, I use this for general data-access.
https://github.com/sudowing/service-engine-template
But once other teams started integrating -- we heard all kinds of feedback.
My thoughts afterward were simply that people under the time pressure to push features daily had different appetites for any friction in their workflow.
We considered the feedback from the larger team and intentionally added support for both REST & GraphQL in our next app. We wanted to support anyone that wanted some exposure to it without forcing anyone. And that had much better feedback from consumers.
And, from the JS PoV, similar burden of the "interior" language
Besides, any sane developer will build an abstraction on top of the fetch request.
The difference to any other JSON reply is minimal.
I've put GraphQL in front of TB-scale data sources with X00,000 tables, and it was clear that (a) GraphQL wasn't designed for anything that big, and (b) if we could get it there, it would be transformational.
This is why I built Trustfall[0]: a system that keeps the elegant GraphQL syntax, and tweaks the semantics to ensure great performance and better expressiveness: left joins / recursion / aggregations / arbitrary filters etc. Trustfall flips the proposition around: acknowledge we're wrapping a database around every data source (API server / database / filesystem / ML etc.) and make it the best possible database it could be.
I gave a talk on it titled "How to Query (Almost) Everything" at the HYTRADBOI'22 conference: https://www.hytradboi.com/2022/how-to-query-almost-everythin...
I also recently used it to build cargo-semver-checks[1], a semver linter for Rust crates where each semver rule is implemented as a query using Trustfall's GraphQL + custom directives syntax.
[0]: https://github.com/obi1kenobi/trustfall
[1]: https://crates.io/crates/cargo-semver-checks
On the BE it's not great, harder to reason about than REST and harder to manage. It's also harder to monitor than traditional REST, since REST makes use of a full range of http header codes (the graphql server we used only used http header 200 by default, we have modified this).
What I recently learned is that the apollo client has support for REST APIs, this is a path that seems interesting to me. We've also been looking at FE libraries for REST that have similar interfaces to the apollo client, if you have suggestions please let me know.
If you have an OpenAPI spec of your REST API you can auto-generate a react-query based frontend client with Orval[2]. Works pretty well, but probably takes a bit more time to set up.
[1] https://tanstack.com/query/v4/ [2] https://orval.dev/
One thing I like about the apollo client is that it handles a lot of the cache invalidation for you, where as react-query it seems to be a bit more of a manual process, how are you and your team handling cache invalidation?
There's pitiful tooling for something like JSON-RPC and no equivalent of OpenAPI for it.
If you use gRPC, there's still less tooling than there is for GraphQL and the primary transport is Protobuf.
Being able to make JSON HTTP requests ("JSON-Transcoding") is a second-class citizen if even supported at all by your server library.
Here's a non-exhaustive list:
- Kotlin: Netflix's "DGS" (https://github.com/Netflix/dgs-framework)
- Python: Strawberry (https://github.com/strawberry-graphql/strawberry)
- .NET: HotChocolate (https://github.com/ChilliCream/hotchocolate)
- Rust: async-graphql (https://github.com/async-graphql/async-graphql)
- Java: GraphQL-Java (https://github.com/graphql-java/graphql-java)
- Scala 2: Sangria (https://github.com/sangria-graphql/sangria)
- Scala 3: Caliban (https://github.com/ghostdogpr/caliban)
Also, the idea that we can just 'go back' is silly.
> GraphQL solves the rough edges of REST that didn’t exist in RPC. Just go back to RPC. Still works great, and now we have modern frameworks like gRPC that make it a joy to use.
I suspect that front-end people like it because it requires less thinking on their part. A GraphQL call can replace a bunch of REST calls, and they don't have to deal with error handling and networking which in the front-end can be really difficult. Pushing that to the back-end makes their lives easier.
I've found that on the back-end GraphQL is more work than REST, because there's a bunch of extra crap you have to do to essentially do the same thing as REST.
And there's a bunch of stuff that's deliberately undefined, like "what do you do if there's a partial failure of your calls?"
If you are hand-crafting interdependent query logic to resolve GraphQL queries from multiple sources and doing that at scale, you may want to look at db adapters and the federation pattern.
Also, GraphQL absolutely still requires error handling in the frontend, and many clients actually provide great facilities for error handling: retrying failed requests, refreshing auth tokens transparently on received auth errors, network state detection, offline functionalities, etc.
Of course, code generation has its own particular set of gotchas and problems (for example, you really don’t want to expose the full functionality of, say, the Prisma api to the world)