7 ms·
I'd also point out that the GraphQL/Relay spec for pagination enforces cursor based pagination: https://relay.dev/graphql/connections.htm https://relay.dev/grap
by stevebmark 4y ago
I'd also point out that the GraphQL/Relay spec for pagination enforces cursor based pagination: https://relay.dev/graphql/connections.htm https://relay.dev/graphql/connections.htm. It's also a really nice pagination spec overall, edges/node/pageInfo are well thought out and flexible.
In my professional experience, lots of devs will implement fetching APIs and not consider pagination, and then when the responses start growing (testing data, use, whatever), user experience sucks. Pagination should be a default API design for anything returning an unbounded list of items.
- Ambolia 4y agoHow do you deal in GraphQL when you have a query hitting with multiple nodes which may return multiple cursors for the different nodes? Seems like a nightmare if you have to check and retry manually for each node, maybe there are libraries that take care of it transparently?
- stevebmark 4y agoHow is this different than hitting multiple REST endpoints for different resources with their own individual pagination? If the client needs to glue together paginated resources from two places, it's a hairy problem no matter what the protocol. A backend for frontend that does this under the hood is one solution to both, or a specialized endpoint that does it under the hood.
- Ambolia 4y agoIn the case of hitting multiple REST endpoints for different resources, on each query it's clear what pagination I'm using and combining the data is just appending it to the final list. In each case the partial results are flat and linear. But in the case of GraphQL, like I may get an incomplete list, or I may get a complete list that will have some fields with missing data, or some combination of both, going down deep depending on the structure of the query. I don't see a clear way to request the missing data without duplicating part of what I already have, and I don't see a clear way to combine the results. But I may be missing something about GraphQL or something about the tools that makes this simple. For example something like this: { users(first: 10000, after: "cursor123") { edges { cursor node { id name friends(first: 10000, after: "cursor235") { edges { cursor node { id name } } } } } } }
- hamandcheese 4y agoIn the relay JS library you can avoid some duplication with fragments. Fragments are pieces of a graphql query that you can include in multiple queries. If you are using flow, the type system will also ensure that you can’t render a component unless you have used the correct fragment in your query. That said, paginating multiple resources on the same page is still going to be complicated.
- stevebmark 4y agoOh. I think you’d handle it the same as rest, make a new individual field query for that friend by ID and ask for the pagination there. I think that would be manual work for graphql or rest, im not aware of anything that does that automatically. It’s also not a case I’ve personally ran into so not sure.
- grahamm 4y agoAgreed, so many times I've raised paging with an internal API provider only to be told they can retrofit it later if needed. Then you start to use production data and bam the one call doesn't work.
- User23 4y agoI disagree. I think pagination is a clumsy error prone kludge. That it performs better than the awful naive approach by additionally burdening the caller doesn’t remotely make it good. The correct approach is a buffered stream with proper flow control. Incidentally that’s what Transmission Control Protocol was invented for. Probably the nicest way to expose this that fits contemporary sensibilities would be as a lazy sequence that does sensible prefetching and asks the server for more data as it’s iterated through.
- freedomben 4y agoI find pagination really annoying on the client, but the majority of the time it does seem like the client doesn't actually need the whole thing so it's a good (and often very necessary) performance optimization. For endpoints where that isn't the case, it's (usually) not too hard to allow a sentinel value for page size that means infinity, so the client really can get it all in one swoop.
- robertlagrant 4y agoWhat are you saying that would be different in practice? What advantages would it have?
- jayd16 4y agoNot sure I agree with the parent but thinking it through, you have a single connection and a cleaner life cycle. Streaming writes and reads could mean back-pressure is possible. A client can consume items as needed as opposed to mapping usage to a page size. There's no worry about wasting a full request on the last page with a single item. In fact there's no worry about round trips at all, it's just a matter of buffer back pressure that communicates the need for more or less. Hmm, when you think about it, its a pretty good way to go.
- User23 4y agoThat’s consistent with what I have in mind. I too think it’s pretty much best of both worlds. You get better efficiency than pagination with the convenience of an API that’s no different from fetching all the data.