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 thepageInfo
property, how to use theafter
argument, 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.
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 ofedges
that is called a connection.
"When you request anything that's pluralized, Shopify's API is implementing a connection specification."
Let’s look at thatProductConnection
.
Build for the world’s entrepreneurs
Want to check out the other videos in this series before they are posted on the blog? Subscribe to the ShopifyDevs YouTube channel. Get development inspiration, useful tips, and practical takeaways.
SubscribeSo, I got the list ofedges
, that's why I had to writeedges
andnode
. Then at the end ofnode
is where I can actually get thetitle
anddescription
.
Introducing thePageInfo
property
There is another property here on the connections calledPageInfo
, and it returns aPageInfo
type that is non-nullable.
Right at the same level asedges
, I'm going to get that field as well and let's actually inspect thattype
to see what it tells me.
It's two booleans. One is calledhasNextPage
and the other,hasPreviousPage
. So let's try this out. I'm going to pressplayagain.
This is saying thathasNextPage
is 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,hasPreviousPage
is 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 eachedge
essentially has an index to say this is a unique identifier of this particularedge
. Not a unique identifier of thenode
, but the actualedge
itself, because connections return a list ofedges
.
Let's jump to the schema definition of a productedge
to explore this a little further. In addition to thenode
that I get back on thatedge
, the other important property here is thestring
.
So I'm actually going to say, tell me about thecursor
as well.
Now, I get a lot more data back in this array ofedges
. Eachedge
has this opaque, unique identifier of thecursor
.
Thecursor
is kind of like the position of thatedge
in 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 actualfield
itself to see what arguments I can supply.
So I'm going to click on the actual fieldproducts
here, not thetype
that gets returned, butproducts
, and these are lists of the arguments that I can do.
Now, I'm only usingfirst
here, 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 lastcursor
that I retrieved is thisstring
.
Build apps for Shopify merchants
Whether you want to build apps for the Shopify App Store, offer custom app development services, or are looking for ways to grow your user base, the Shopify Partner Program will set you up for success. Join for free and access educational resources, developer preview environments, and recurring revenue share opportunities.
Sign upEmploying theafter
argument
So what we’re going to do, just for simplicity's sake, is we’re going to copy thatstring
and I'm going to supply a second argument to say after this particularcursor
.
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.
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:10
and 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.
Apparently there aren't actually 50 products in the store. It's either 50 or less. Now bothhasNextPage
andhasPreviousPage
are 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 ofcursor
andpageInfo
and let's say, onproducts
, I was also interested in theirvariants
and theirtitle
.
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
,ID
of eachvariant
, and thetitle
of eachId
.
现在我可以使用相同的分页字段level of variance.
So next toedges
there waspageInfo
, and on theedge
itself was a property calledcursor
. We also want to expand the information onpageInfo
forhasNext
andhasPrevious
.
Now I've got some nested pagination going on here, so I can do pagination at every level of lists that I have.
What this is saying is that I've requested the first twovariant
s, but there is actually another page ofvariant
s for this product. For this next project down here,Classic Varsity Top
, that also has anextPage
and 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: thequery
argument. If you missed it, you can start at the beginning of this series withGraphQL operation names and variables.
Build for the world’s entrepreneurs
Want to check out the other videos in this series before they are posted on the blog? Subscribe to the ShopifyDevs YouTube channel. Get development inspiration, useful tips, and practical takeaways.
Subscribe