How to Work with GraphQL Pagination

graphql pagination

This is a complimentary blog post to a video from theShopifyDevs YouTube channel. In this article, Chuck Kosman, a Launch Engineer at Shopify Plus, dives deeper into the essential features you should know when working with GraphQL, focusing on GraphQL pagination. This is the fourth video in a five-part series of tutorials designed to improve your knowledge of the language. You’ll learn about thepageInfoproperty, how to use theafterargument, and explore the advantages of working with cursor-based pagination.

Note: All images in this article are hyperlinked to the associated timestamps of the YouTube video, so you can click on them for more information.

Introducing a new product query

We’ll be picking up where we left off in part three of the tutorial where we looked at working withGraphQL fragmentsas a way to recycle fields. You can also step back and read up onwhat is GraphQLif you’d like an overview of getting started and the language itself.

Now, I have totally removed what I was working with in the last tutorial, and I've written a new query, which I called, using operation names,query ThreeProducts. All this does is retrieve the first three products in the store. So, what I'm going to do here is I'll just pressplayand verify that this works.

graphql pagination: gif taken from youtube video

We get these three apparel items in my test store.

You might be wondering, well, If I get the first three, how do I get anything beyond the first three? How do I start working with pages on GraphQL?

Just as a recap, If you read our article ongetting started with GraphQL, you would know that when you request anything that's pluralized, Shopify's API is implementing a connection specification. Essentially, when you get anything plural, the type that you get back is a list ofedgesthat is called a connection.

"When you request anything that's pluralized, Shopify's API is implementing a connection specification."

Let’s look at thatProductConnection.


graphql pagination: gif taken from youtube video

So, I got the list ofedges, that's why I had to writeedgesandnode. Then at the end ofnodeis where I can actually get thetitleanddescription.

Introducing thePageInfoproperty

There is another property here on the connections calledPageInfo, and it returns aPageInfotype that is non-nullable.

Right at the same level asedges, I'm going to get that field as well and let's actually inspect thattypeto see what it tells me.

graphql pagination: screenshot of pageInfo taken from the video

It's two booleans. One is calledhasNextPageand the other,hasPreviousPage. So let's try this out. I'm going to pressplayagain.

graphql pagination: screenshot of pageInfo taken from video

This is saying thathasNextPageis true. So there is another page of results, and that means that there's at least one product that hasn't been captured in this particular page of results.

Now, because this is the first page, there's not a page before this one. Therefore,hasPreviousPageis false.

So how do we actually get at that next page of results? What do I look to?

You might also like:How to Build a Shopify App in One Week.

Using relative cursor-based pagination

The way that Shopify has implemented GraphQL is relying on the connections specification that's part of the relay library. Many other GraphQL schemas have chosen to adopt cursor-based pagination over offset-based pagination. There are very good performance reasons behind the scenes for doing this.

"The way that Shopify has implemented GraphQL is relying on the connections specification that's part of the relay library."

For now, know that the way that cursor-based pagination works, is that eachedgeessentially has an index to say this is a unique identifier of this particularedge. Not a unique identifier of thenode, but the actualedgeitself, because connections return a list ofedges.

Let's jump to the schema definition of a productedgeto explore this a little further. In addition to thenodethat I get back on thatedge, the other important property here is thestring.

So I'm actually going to say, tell me about thecursoras well.

graphql pagination: gif taken from youtube video

Now, I get a lot more data back in this array ofedges. Eachedgehas this opaque, unique identifier of thecursor.

Thecursoris kind of like the position of thatedgein the list.

Let’s say I needed to get the next three pages of results. What I would do is I'm going to look at this product's query and I'm going to take a look at the actualfielditself to see what arguments I can supply.

So I'm going to click on the actual fieldproductshere, not thetypethat gets returned, butproducts, and these are lists of the arguments that I can do.

graphql pagination: gif taken from youtube video

Now, I'm only usingfirsthere, that's kind of the most basic one. But this goes along with another argument that I can use. What I'm going to say is, the lastcursorthat I retrieved is thisstring.

Employing theafterargument

So what we’re going to do, just for simplicity's sake, is we’re going to copy thatstringand I'm going to supply a second argument to say after this particularcursor.

graphql pagination: screenshot of syntax taken from youtube video

Now, let's just take a look at the products here. I got backOcean Blue Shirt,Classic Varsity Top, andYellow Wool Jumper.

If I’m issuing a request for the next page of results, I should expect that none of these show up. All my products are titled uniquely, so we’re saying, “Give me the first three productsafterthis lastcursor.”

I'm going to pressplay.

graphql pagination: gif taken from youtube video

The titles that I get back here are none that matched the last set of results (Striped Silk Blouse,Floral White Top, andClassic Leather Jacket). And importantly, the page info has changed too.

Apparently there's still another set of results to be had here and there is now a previous page. So the page information is telling me that there is both a page after this, and a page before this.

You might also like:How to Use GraphQL Fragments.

I'm not sure how many products I have in the store, so this will actually be a good test.

Let's say I have ten products in the store and I change the argument tofirst:10and I just get the first page of results. It looks like I have another page.

If I were to increase this to something like fifty products and I saidfirst:50, let’s see what happens when I pressplay.

graphql pagination: gif taken from youtube video

Apparently there aren't actually 50 products in the store. It's either 50 or less. Now bothhasNextPageandhasPreviousPageare False.

我一直在使用后,但如果你想要的to go in reverse order, there's a couple of different things you could do. You could say you want the last elements from the list and you could say you want the last elements before somecursor. You could also reverse the listing of these things so that instead of listing them in the order of created at ascending, you'd get them in order of created at descending. So you'd start with, say, the product that was created last.

You might also like:How to Use GraphQL Aliases.

Nested GraphQL pagination

Pagination is also nested.

让我们回到一个更小的子集的搜索结果。I'll call itFirstThreeProducts. I'm going to get rid of the pagination information at the top level of products. So, I'm going to get rid ofcursorandpageInfoand let's say, onproducts, I was also interested in theirvariantsand theirtitle.

graphql pagination: gif taken from youtube video

So variants return a list, a connection type, which is a list ofedges.

For whatever reason, let's naively say that I want the first twovariants, but there's actually more than that. Let’s say I also wanted theedges,node,IDof eachvariant, and thetitleof eachId.

现在我可以使用相同的分页字段level of variance.

So next toedgesthere waspageInfo, and on theedgeitself was a property calledcursor. We also want to expand the information onpageInfoforhasNextandhasPrevious.

Now I've got some nested pagination going on here, so I can do pagination at every level of lists that I have.

graphql pagination: gif taken from youtube video

What this is saying is that I've requested the first twovariants, but there is actually another page ofvariants for this product. For this next project down here,Classic Varsity Top, that also has anextPageand so on and so forth.

I could use exactly the same principles per the schema to do things like after this particularcursor.

Stay tuned for the final part of this tutorial where we'll be looking at a special argument that you can supply to any field that returns connections: thequeryargument. If you missed it, you can start at the beginning of this series withGraphQL operation names and variables.

Grow your business with the Shopify Partner Program

Learn more