But I don't think it addresses why I'd want a "smart" GraphQL client: normalized caching on the client.
Say I have a dashboard where multiple panels on a given page make their own requests, since the panels are shared between many pages. But they share some objects. If I get updated data in a request from one panel, I'd like to see that update in all panels, without triggering more requests.
Side note that a magic layer to have each of those components combine their requests into one would actually hurt performance, since it's better to load the requests in parallel. And manually merging them into one would be quite a chore.
Absolutely true! When I worked on this at $prevCo, it was tricky and sometimes caused bugs, unexpected behavior, and confused colleagues.
I will say that a proper implementation of a normalized cache on the client must have an ~inherent (thus generated) understanding of the object graph. It also must provide simple control of "whether to cache" at each request. Most of the problems we experienced were a result of the first constraint not being fully satisfied.
My impression is that Apollo does a good job on both of these but I haven't used it so I can't say.
I'll also note that the approach of "when one component makes an update, tell all other components on the page to refetch" sounds like a recipe for problems too – excess server/db load, unrelated data changing in front of users' eyes (and weird hacks to prevent this), etc.
Of course, with the wundergraph architecture, it sounds like answer to these questions would simply be to load a given table only once per page – which means no more defining queries on the "panel" components in the dashboard, for example.
All tricky tradeoffs! The right answer depends on what you're building. The Wundergraph approach sounds pretty cool for a lot of cases!
Does it lead to greater complexity somewhere, and all the issues around making that complexity bulletproof? Sure. But the user experience is so viscerally different that some will demand it. I think it’s admirable to work on getting that complexity correct and properly abstracted so that it can be re-used easily.
I think Jens Neuse is making two important observations about GraphQL:
1. GraphQL's single URL/endpoint [1] is possibly an anti-pattern
2. ETags are important for Cache-Control and Concurrency-Control on REST endpoints
The concept of prepared statements is useful for my SQL-centric brain. WunderGraph effectively creates a REST endpoint for each prepared statement (GraphQL DML). Like prepared statements in SQL, WunderGraph uses query metadata to determine the types of input parameters and the shape of the JSON response.
Kyle Schrade makes an important point about canonical GraphQL queries: response payloads can be reduced by filtering JSON fields, similar to SQL projection (i.e. the columns specified in the SELECT clause). It seems that WunderGraph can potentially support both approaches by allowing optional GraphQL queries on each REST endpoint that can be used to filter the endpoint specific JSON response.
[1] https://graphql.org/learn/serving-over-http/#uris-routes
It might be a useful exercise to prototype an online shopping site using WunderGraph.
I’d say that’s completely fair still, just wondering. I’d also say I understand the carefulness and stance on “smart clients,” i.e. normalized caching, which is why this isn’t a default in urql, but without it I think the discussion here is much more nuanced.
It’s so to speak much easier to rely on an argument with a smarter client and the Apollo ecosystem, than the rest. Anyway, I like your approach with Wundergraph so I’ll definitely check it out!
Another thing is mutations - does WunderGraph support mutations at all yet? Security for those is also even more important, as you might want to restrict what entities you can attach to the entity you're creating etc.
I guess the root of my question is how much business logic can you achieve with WunderGraph itself? It's probably not something that's necessary if I really think about it, if it just handles the authN and then passes tokens with claims nad user IDs to the data sources, Hasura/Postgraphile et al can handle the row-specific authZ and business logic, and then WunderGraph can just be the BFF for each app client. I'd still definitely use it in that setup, as the generated clients and federation subscriptions would be a marked improvement over Apollo for me.
Mutations are fully supported. When generating clients all we do is treat mutations like POST requests and queries and subscriptions like GET http2 streams falling back to http1 chunked encoding.
WunderGraph doesn't want to contain business logic. We are the front door, making everything secure and establishing a stable contract between client and server. We mediate between protocols and we map responses so that every party gets data in the format and shape they expect. Other than that, if you want to add custom logic just run a lambda with any of the supported protocols, e.g. GraphQL, REST and in the future gRPC, SOAP, Kafka, RabbitMQ, etc. and we do the mediation. But as were the middleware layer I'd try to not put business logic into this.
That said I'd love to get in touch and discuss how WG can add value for you.
But what it does do is constrain. Now, constraints are great. They’re always a great tool to introduce new innovations. What I’m ultimately thinking is, how much do you bring to the table compared to persisted queries and tools like GraphQL Code Generator and the added flexibility that comes with those tools?
Genuine questions of course, not criticism
Next we're able to execute the persisted query on the edge using etags for low latency.
WunderGraph adds the capability to use @stream & @defer on top of any existing GraphQL or REST API. You don't have to change anything on your existing GraphQL server. This works especially great with Apollo federation. WunderGraph is a replacement for Apollo gateway. We support federation with subscriptions, @defer and @stream, another unique feature to WunderGraph. The generated code gives you simple to use hooks, in case of react, to fetch data or streams.
Finally the generated code is authentication aware. WunderGraph has its own OIDC server. Generated clients know if authentication is required for a specific persisted query. This way a query will wait until the user authenticates and then fire off.
I think this should be enough. I don't want to get too much into the details as there are a lot more benefits.