Handle pagination on read action with GraphQL

Eduardo B. Alexandre
2023-02-07

Eduardo B. Alexandre:

In my read action, I have this line enabling pagination:

 pagination offset?: true, countable: true, default_limit: 2, required?: true

In the playground, I can see that the query accepts the fields limit and offset, but the query response doesn’t return anything related to the pagination (see image)

ZachDaniel:

Yeah, thats all that we return at the moment. There is an issue in ash_graphql for returning additional information IIRC

frankdugan3:

If you want to subscribe to the issue: https://github.com/ash-project/ash_graphql/issues/39

frankdugan3:

Meanwhile, I think if you change it to use the relay version, it gives more info, right?

ZachDaniel:

It probably does, at the expense of being a more confusing response

Eduardo B. Alexandre:

Yep, using relay fixed it for me.

ZachDaniel:

what specific info did you need?

Eduardo B. Alexandre:

For offset?

I would expect fields like current_page, limit_per_page, has_next_page?, has_previous_page? and total_pages

ZachDaniel:

Yeah, makes sense 👍 Just making sure!

ZachDaniel:

Since we’ve got an issue tracking this, will close.

Eduardo B. Alexandre:

<@197905764424089601> Sorry for asking for that, I know you probably already have a lot on your plate. But do you have any idea when offset pagination would be implemented in AshGraphQL?

Using relay worked fine with me, but using cursors for pagination means that I can’t create numbered pages which is a requirement for the product I’m working. So, in the end, I can’t use it and need to find a solution that would use offset.

ZachDaniel:

Well, offset pagination is implemented, but you’re asking when the additional metadata will be added?

ZachDaniel:

You can get things like total_pages by using the count that can be optionally returned

ZachDaniel:

countable: true on the pagination config

ZachDaniel:

has_next_page? is count > offset + limit , current_page is (offset + limit) / limit , has_previous_page? is offset > 0limit_per_page is limittotal_pages is count / limit

ZachDaniel:

I think the main one you really only need something special for is has_next_page , because on our end we know if there is a next page without having to count

Eduardo B. Alexandre:

Yes, what I meant was to AshGraphQL see that the offset pagination option is enabled and so return these fields automatically in the query response

ZachDaniel:

I don’t think we would necessarily want to add all of those metadata fields you mentioned though

ZachDaniel:

has_next_page would be useful, but the rest can be determined already without the server doing additional work

ZachDaniel:

And even has_next_page can be calculated if you have countable: true

frankdugan3:

IMO, I would want to optionally select those fields, kind of like how we can currently select count . Sometimes it’s nice 1) to not have to do that in JS/whatever consumer language is, 2) avoid simple errors in calculating those things incorrectly – DRY it up. If they’re selectable fields, the server simply wouldn’t have to do the work, assuming they were implemented as some kind of resolvers, right?

ZachDaniel:

Well, yeah

ZachDaniel:

Although honestly we’d probably jsut do the work

ZachDaniel:

😆

ZachDaniel:

its just some multiplication

ZachDaniel:

or division or w/e

frankdugan3:

I mean, not specifically all those fields, but the typical calc ones that you’d consume in a front-end for pagination UI.

ZachDaniel:

🤔 well, I can add has_next_page for now because that one actually contains an optimization that only the server can know about

frankdugan3:

Even returning the count/limit in the query (even though it’s known as the parameter) can be nice in the result because depending on the UI component API, that info might be opaque in places that only the results were being passed down.

ZachDaniel:

I get what you’re saying about the other fields, and its a backwards compatible change to add them

frankdugan3:

Again, the idea of it being top-level optional fields like count means it doesn’t have to run/return if the user doesn’t ask for it.

ZachDaniel:

Yeah, but it also encourages them to ask the server to do work that it doesn’t have to do

ZachDaniel:

The technically most optimal thing is for the client to compute it if they want to

ZachDaniel:

its yak shaving at this point, it takes like a picosecond to add and divide two integers 😆

frankdugan3:

Yeah, that’s my take. Could always make it optional too, so those that don’t want to serve that data can disable it.

ZachDaniel:

but I just pushed support for has_next_page up.

ZachDaniel:

If someone wants to add those other fields, the places I just edited can be modified to support all the other fields 😄 PRs welcome!

Eduardo B. Alexandre:

Yeah, now that I think about it, it makes sense 😅

Eduardo B. Alexandre:

I will take a look after work

frankdugan3:

I’ll probably do that in a month or two when I start getting more into supporting GraphQL at work. I know that will be asked for by my end users. lol