The main advantage is that the query is resolved at runtime. It only queries for exactly what your component needs. No over-querying. No sharing queries across components, which is a huge mistake people make.
Have you found a way to get build errors with GraphQL queries? I only ever get them during runtime when the request is made, I assume because that's the point at which the back-end and front-end disagree on what you're requesting.
If you generate types from your GraphQL queries, they are validated against the schema at that time (so you'd get schema errors then, of course there can still be network errors, server errors or user/semantic errors at runtime)
Using Typescript,GraphQL-codegen, and Hasura, I can build correct-by-construction React apps. GraphQL-codegen & Hasura introspect the DB to type the query result, and typescript confirms my JS is not accessing any of those fields illegally.
It’s pretty killer to open GraphiQL, write a new query, drop it into a graphql file in my repo, rerun the codegen, and be able to have type safe operations on the queried data.
Also makes me completely unsure why anyone would want what the OP is but that’s ok
I think the part that's throwing people off (including me) is if I'm looking at that main example, how do I get type completion on this line:
Hello {query.me.name}!
query dot me dot name should all have type completion. And in most TS "frameworks" you have some way to type hint this all out. us TS folk are not seeing the type hints in the example. Maybe it works in VSCode like that, but totally confused how it does.
Believe me, I'm super interested in this project and it would save a ton of time if it's doing what some of us are hoping :)
It does autocomplete with types on that line, and yes, it’s really that cool.
Disclosure: I funded the development of version 2, and have written a large app using it. I am very happy with it, and believe it’s the best data fetching solution around.
I'd say you're broadly right, the key idea is that your client code has a facade over the fact that you're using GraphQL, so it looks cleaner -- it's "just JavaScript". Whether this is an advantage or not is largely down to preference.
The "Why" section in the docs is a pretty good summary:
"I wanted a GraphQL client that lets you forget you're using GraphQL, whilst tackling some issues shared across all existing GraphQL clients"
The fact that it's resolved at runtime isn't necessarily an advantage, it locks you out of some performance and security patterns. I believe GQLess is investigating support for static extraction of queries at build time.
It's an interesting API, I'm not entirely sold on the idea of disguising the fact that you're using GraphQL though.
This looks like it has a shot at being a better developer experience than Relay while still encouraging the use of nested queries (unlike clients like Apollo and urql). Nice.
You can’t pass along the result (not exactly but that’s how it looks) of a query to a component and query more things on it.
An example might be something like, you have a page showing a user, and you have a ProfilePicture component with certain data requirements (e.g. get picture at 100X100). It would be nice if you could pass down the user and have the ProfilePicture component query the data it needs, with this being merged into the parent request.
In Relay this kind of thing can be done with useFragment.
In this solution it seems you could just pass the user.
Apollo/urql don’t support this pattern, everything must be in one top level query, or multiple queries (bad perf).
The primary example code relies on Suspense, meaning that loading behavior will be handled by a parent/ancestor <Suspense /> component and not in the component itself. I think they default to showing this pattern since it is the “future” of React. There is an alternate version of the API where you can get a loading boolean for imperative control.
The useQuery hook’s opts have an onError property that accepts a callback.
I also don’t see anything about union types. That definitely seems like the hardest thing to reverse construct based on usage, since the underlying proxy wouldn’t know what you’re doing with __typename.
It generates types via CLI statically up front, all queries are then fully typed, only the final request is generated at runtime which means you never fetch anything except what you need.
One of our requirements is to disable schema downloading in production in apollo server. (We can have it enabled in dev/local). Can this work if that is disabled? (Yes we know this is silly but our auditor caught it)
From my understanding this should work as the schema is introspected ahead of time. This gives all the type information needed for the `useQuery` hook to work properly. Just the queries themselves are generated at runtime; there shouldn't be any need to introspect the schema then.
Where this might have an issue is with persisted queries. But then you'd need some sort of client/server build tooling to keep them in sync.
Cool for prototyping, but likely difficult to maintain over a longer period of time.
Just like with an ORM on top of a DB, if one needs to to performance optimization or support parallel app versions and ensure backwards-compatibility of queries, the actual queries are useful if not essential to know and manage.
There’s no reason all of this isn’t supported as well if not better in GQless than any other client.
You can hoist the query logic if you need to ensure it stays static for some reason.
I’ve built a very large app with this and am perfectly happy with the model, it has many upsides vs having to manually link strings into views, like never overfetching and having fully typed queries without any plugins.
I conclude that it will be incompatible with hasura Allow-list (or lead to explosion of Allow-list for all possible combinations which is impossible in practice)
So it could look nice but makes unusable in case you rely on Allow-list for security.
40 comments
[ 5.5 ms ] story [ 109 ms ] threadSo your application does not need to "talk in GraphQL".
Does it mean that we get errors at runtime and not build time, too?
It’s pretty killer to open GraphiQL, write a new query, drop it into a graphql file in my repo, rerun the codegen, and be able to have type safe operations on the queried data.
Also makes me completely unsure why anyone would want what the OP is but that’s ok
You get the same advantages pretty much, and you have less likelihood of querying for unused data.
I prefer this will validate our component for correct schema usage at build time.
Believe me, I'm super interested in this project and it would save a ton of time if it's doing what some of us are hoping :)
Disclosure: I funded the development of version 2, and have written a large app using it. I am very happy with it, and believe it’s the best data fetching solution around.
The "Why" section in the docs is a pretty good summary:
https://gqless.com/intro#why
"I wanted a GraphQL client that lets you forget you're using GraphQL, whilst tackling some issues shared across all existing GraphQL clients"
The fact that it's resolved at runtime isn't necessarily an advantage, it locks you out of some performance and security patterns. I believe GQLess is investigating support for static extraction of queries at build time.
It's an interesting API, I'm not entirely sold on the idea of disguising the fact that you're using GraphQL though.
An example might be something like, you have a page showing a user, and you have a ProfilePicture component with certain data requirements (e.g. get picture at 100X100). It would be nice if you could pass down the user and have the ProfilePicture component query the data it needs, with this being merged into the parent request.
In Relay this kind of thing can be done with useFragment.
In this solution it seems you could just pass the user.
Apollo/urql don’t support this pattern, everything must be in one top level query, or multiple queries (bad perf).
It always feels like magic.
How do you deal with union types? The docs seem completely scant on that.
Otherwise very interesting approach.
My guess is its going to be something like `undefined` means loading and `null` means null.
I also don’t see anything about union types. That definitely seems like the hardest thing to reverse construct based on usage, since the underlying proxy wouldn’t know what you’re doing with __typename.
Colocating data requirements next to where it is using it without writing it two times is awesome!
Where this might have an issue is with persisted queries. But then you'd need some sort of client/server build tooling to keep them in sync.
Just like with an ORM on top of a DB, if one needs to to performance optimization or support parallel app versions and ensure backwards-compatibility of queries, the actual queries are useful if not essential to know and manage.
You can hoist the query logic if you need to ensure it stays static for some reason.
I’ve built a very large app with this and am perfectly happy with the model, it has many upsides vs having to manually link strings into views, like never overfetching and having fully typed queries without any plugins.
I conclude that it will be incompatible with hasura Allow-list (or lead to explosion of Allow-list for all possible combinations which is impossible in practice)
So it could look nice but makes unusable in case you rely on Allow-list for security.
It could be good for prototyping.