Hacker News new | ask | show | jobs
by Lx1oG-AWb6h_ZG0 1949 days ago
The main advantage I’ve found with GraphQL is the normalized cache in client libraries like Apollo or Relay. It allows components to just ask for the data and not worry about how it’s fetched/stored/updated. The secondary benefit is that _some_ (not all) of the data plumbing can be moved from the frontend code to the backend, which makes for faster apps. Beyond that, GraphQL is more of a hinderance than a help... its type system in particular is brain dead and easily the worst part of the entire experience (seriously, why _is_ there a difference between inputs and types? Why can’t you define input unions, or maps, or recursive structures?)

Is there any equivalent for the latter with swagger? Yes, you can do everything in there with custom redux middlewares or sagas/observables, but it’s more glue code you have to write and maintain.

2 comments

> The main advantage I’ve found with GraphQL is the normalized cache in client libraries like Apollo or Relay. It allows components to just ask for the data and not worry about how it’s fetched/stored/updated. The secondary benefit is that _some_ (not all) of the data plumbing can be moved from the frontend code to the backend, which makes for faster apps.

Is this something you couldn't achieve with the idiomatic rules on HTTP request types, and serialization of HTTP requests parameters? It really depends on where you're trying to do the caching and what kind of caching you're trying to do.

A lot of work has gone into HTTP headers, method semantics, and other details in order to facilitate caching. The "backend for frontend" pattern has been very popular as of late in order to try and shift the plumbing load, exposing endpoints that are catered to certain clients to boost efficiency -- would that be good enough for a corollary in OpenAPI land?

The backend for frontend pattern is exactly why I got sold on GraphQL. We had a pile of relatively low value server code that could be replaced a GraphQL resolver and the client got all of the advantages of that pattern. The move to GraphQL genuinely freed up a lot of our time to work on more important problems. This was on a smallish team so that time mattered.
It looks like you've picked the right tool for the job in that case, and I can't argue with that -- but the submission is for tooling that people have created in Swift for a problem that was already relatively solved by OpenAPI bindings for Swift.

Would you mind going into what that low value server code was doing? Was it simply aggregating results of multiple requests? It's quite possible it wasn't that hard to solve with slightly more intelligent (but not a completely separate paradigm) code to start with. However all-in-all I'm not out to argue that GraphQL doesn't improve velocity. I'm saying that the tooling that it has built in (pipelining, horizontal/vertical filtering, etc) could have been available from REST, and gained all the other benefits without a dramatic paradigm shift but no one seems to have bothered, and instead we're finding ourselves rebuilding bits that were already available/worked out in OpenAPI land for a few features that weren't too far away/hard to implement there.

FWIW this was ~2015ish, I'm not sure what the state of OpenAPI was at the time.

> Was it simply aggregating results of multiple requests?

Pretty much. The company I was at was an early proponent of microservices so we had to have a service that operated as our entry point to all of it. Thats easy enough, but layering on versioning of the APIs for native apps on different platforms added complexity that definitely didn't seem worth dealing with in our at the time REST paradigm. We did have frameworks that generated clients for different platforms against that API so I'm not even talking about the boilerplate of sending and parsing JSON.

Cool thanks for sharing this -- it's come up multiple times in this thread and it seems I didn't weigh this point enough.

Maybe this is enough to really make GraphQL or a similar system worth it -- GraphQL and Falcor both existing as similar but separate technologies probably says something about just how problematic non-GrapQL-like patterns are at scale, and if your had a good experience at smaller scale as well then it's worth reconsidering.

There is no different paradigm. Both GraphQL and "REST" as it's usually implemented are RPC protocols. GraphQL just doesn't pretend it is not.
If you do a survey of front end data fetching frameworks, they basically land in two categories:

- API-agnostic: react-query, rtk-query, swr

- Declarative queries (e.g. GraphQL): apollo-client, relay, urql

A major difference to notice is that the API-agnostic libraries do not handle normalizing the data before caching it. Instead, they cache the data based on some key related to the request. So you can potentially fetch and cache two different versions of the (semantically) same information, leading to UI incoherence. The various API-agnostic libraries have ways of solving this by explicitly creating relationships between different requests so that you can manually say, "when I fetch with this key, also trigger a re-fetch of any components subscribed to these other cache keys." This is coarse, but for many cases "good enough" in contexts where you don't have full control over the API you are fetching data from.

In order to leverage a normalized cache, the layer between the cache and network needs to intimately understand what data is returned by which request so that it can support things like stale-while-revalidating, re-rendering on refetch of the same data from another part of the page, etc. Describing all of the data that could possibly be returned by an endpoint is tedious and error prone, as APIs can be dynamic in what they return and backend changes could easily lead to breaking any assumptions the frontend might make about an opaque endpoint.

Now if you have more control over how a backend behaves and buy-in on solving this problem full stack, you can start to build some of these assumptions into both layers. For instance, you could require all endpoints to be fully documented via swagger, and the front end could use the swagger JSON doc to map endpoints to data potentially returned by a response. You would also need a pattern to key each request with what entity (type + ID) it is responding data with before it completes; HATEOAS provides a standard of relating URIs to entities and would solve this problem.

So you can see that this normalized caching problem can be solved without GraphQL, as long as the backend and frontend can agree on a set of standards and requirements such as REST + HATEOAS + Swagger. Personally, if someone is passionate about solving this problem, I would recommend GraphQL, but it is up to each team to decide on what solutions meet their requirements.

If you just want the syntax and caching, you might try React Query. Haven't used it myself but it looks like it's Apollo-inspired.