This is a complementary blog post to a video from the ShopifyDevs YouTube channel. This is the third post from a four-part series created by Zameer Masjedee, a Solutions Engineer with Shopify Plus.
In the first part of this series, An Introduction to Rate Limits, we covered what exactly an API rate limit is, and how Shopify uses the leaky bucket algorithm. We followed up with a second post, API Rate Limits and Working with GraphQL, to explore the many benefits of GraphQL.
In this post, I'll take all the principles introduced to you in the first two parts of this series, and apply them in a practical application in a development store. First, I'll walk you through what you’ll need to get started. Then, I'll teach you how to make some key real-time requests to the Shopify API.
By the end of this article you'll have a practical understanding of how to make real requests to the Shopify API and how to responsibly consume your rate limit without running into any errors.
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.
What you’ll need to get started
Today, we're going to take some of the best practices and ideas we previously learned and implement them, all while employing some essential business logic. All this will be done in an application that we're going to be working on for a development store. I’ll be using VS Code but feel free to use whatever IDE you like working in.
Our example use case
In the example store that I’ve created, we have a bunch of products that are all associated with a commodity. They're gold bracelets, and as we know, the price of gold fluctuates. In our development store, we create products whenever orders come in, so we need to ensure that we're charging the right amount for them. As the price of gold changes, the price of our products also needs to change. There will be recurring time intervals where we have to take the entire product catalog and update the prices based on the most recent price of gold on the market.
There are a few steps we need to take to achieve this goal. First, we’re going to use a Node application to take a look at the products in my shop that might be impacted by an adjustment in the price of gold. Then, we’re going to implement some best practices in order to update those prices. We’re going to do all this in a way that respects the API rate limit and ensures your app isn't getting throttled.
Before we proceed, If you're new to GraphQL, I'd highly recommend checking out the GraphQL video series on the ShopifyDev’s YouTube Channel by my good friend Chuck Kosman. He walks you through all of those elements, including aliases, variables, and anything that I discuss in this post that might be unfamiliar. You can watch the first video of his series below, or read our accompanying tutorial.
We're using GraphQL to control our variables, and its
request package to be able to make some requests pretty simply.
For this tutorial, I'm not going to build an official Shopify app. That would mean going through the app CLI tool and configuring it that way. We ultimately just want to test it out to see what it would look like if we did have this business logic in our application.
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 up
How to retrieve product information
The first thing that we're going to do is make a request. This is demonstrated in the below highlighted query to Shopify.
products(first: 200, query: “tag:gold”) is requesting to retrieve the first 200 products that match our query. In this case, we’re interested in any product that has been tagged as
gold. We’re also asking for the
id of those products. This is an easy way for us to identify the relevant products out of the entire catalog.
We’re interested in adjusting the price, and we know that the price in Shopify lives on the
variant, so we need to take a look at the
variant associated with that product. Finally, we’re going to issue a request for the
weight, because that's what we're going to use to calculate the new price. We need the
weight to determine what to charge going forward.
Another thing to note is that I'm cheating a little bit in the above example when I say
variants(first: 1). I know that every single one of my products only has a single variant, because that's how I've set up my store. You might have to play around with a larger number and take a look to see if products have more than one variant. We support up to 100 variants on Shopify, and that would result in some pagination, as you're building a more nested query. For our purposes,
variants(first: 1) works fine.
The above shows that we’re making a request,
graphQLClient.request, with our straightforward
query. We’re going to capture those results
(catch((error) => console.log(error)) and print them onto our console,
console.log(JSON.stringify(queryData, undefined, 2)).
Let’s take a look at what happens when I execute this query:
You can see that the request yielded 200 different products. If we run another request for 10 products, it will yield 10 products. It's important to understand that the response we get starts with the
products key in JSON, and then we get our
Each of these
edges represents the
object or the
node that we're interested in, which happens to be a
product. For each of these
nodes, we have the
id and the
variantss that are also associated with that
product. This is the information I need to be able to implement my app.
How to identify the API rate limit of your app
We know from the previous tutorials that there are costs associated with making a query or issuing updates. When doing so, we want to be able to get a sense of how much room we have left in our API rate limit. Shopify will provide this information to you in the form of an extension to your response. The only thing is, we aren’t necessarily able to grab it with the original library above by making a standard request, so we’ll have to issue a
rawRequest to capture metadata and available rate limit
Below our standard request, we have an additional form.
This form uses the
rawRequest input, which makes the exact same request with the same
query, but with some additional information. Instead of getting just a data set back, we're also getting the
statuses that are part of that request.
In this example, I'm making the exact same request as above, but also capturing and printing out the available rate limit after this request goes through.
When we issue that request:
We see that we have 958 rate limit points available, in addition to the data we’re capturing. Recall that our bucket fills up at 1,000 points, so we have a lot of room left.
Updating your products with individual mutations
The next step we want to take in our process is to update these
products. To do so, we’ll make a mutation for each of these products individually.
Remember that when working with GraphQL, you’re charged one point for every nested property or data field that you're capturing. On the other hand, running a mutation costs 10 points, meaning each of these different products is going to cost 10 rate limit points.
You can see how if I'm going to be making a number of requests, I would run through 958 rate limit points pretty quickly.
Recall that we’ve requested our data. The next thing that we’re going to want to do is action it. We want to take every single one of the product
Ids that are returned, and run them with a mutation on them. I need to be able to fetch the
Id from the request.
How are we going to do that?
You might also like: An Introduction to Rate Limits
Step 1: Indexing into your array by defining a new variable
We see that our request outputs an
array of different
JSON objects, so we could index into that array. We’re going to do so by defining a new variable.
I'm going to call it
const edges = data.products.edges. I could even call this
const productedges = data.products.Edges. That submits a request to look at all that data, which comprises an entire
products, and then
Step 2: Building out our
Now, what we want to do is loop through each one of these
edges so that we can access each
product independently. We do that by writing a
for (let edge = 0; edge < productEdges.length; edge++)
for loop allows us to index into each of the individual
arrays that we get back. But there’s some particular data that we need. So, under our
for loop we’re going to write the following code:
const productId = productEdges[edge].node.id
This is saying that I want the
productId which is actually equal to (
productEdges. Then I need to index into the
node key, and then the
The next thing we’re requesting is the
variantId, written in the following code:
const variantId = productEdges[edge].node.variants.edges.node.id
This is saying that similarly, we're going to request
productEdges, nest again into the
node, but this time into
edges as well. Keep in mind that
edges is still an
Ideally, this request would be paginated over a couple of different options, but remember I’m cheating and I know that we only have a single
variant, so I'm going to go and grab the first one,
. Finally, we’re going to go into the
node to get the
The request for
variantWeight looks similar to the request for
variantId. It’ll look something like this:
const variantWeight = productEdges[edge].node.variants.edges.node.weight
Now we’ve written in all of our specifications. This allows us to access all the different data points that I know from my objects I wouldn't need to actually implement the mutation. Next, we’re going to look at how to update the price of the new product.
How to update your products prices
There are a few steps involved in responsibly updating the prices of your products, which are outlined below.
First we want to update the price of the product. Updating the price of the product looks like this:
This is basically saying that
updatedPrice is equal to (
=) the weight (
variantWeight) of the product multiplied by (
*) how much it weighs (
We’re actually going to fix it to two decimal points (
toFixed(2)), representing cents, because Shopify expects a double in terms of the data type in the request input.
Linking the mutation to your
Next we’re going to have to pull up the mutation to update the price of a product. For simplicity's sake I’ve copied that, so I'm going to insert it into our function and our
Now I’ve created a variable called
productUpdateMutation, and I know that within Shopify, this mutation is called
productUpdate. It expects an input field of type
ProductInput. It will also return to us the
id of the
product that's been updated, because that's what we're requesting.
Fantastic. There we have the mutation.
The next thing we need to do is create the input. We can actually take a look in our
productInput documentation for more information on what this looks like. It outlines all the different input fields that we can get access to, including the
For this example, all we’re interested in is the
[ProductVariantIntput ! ] because that's where the price lives.
The documentation tells us that we’re going to have to provide an
variants key, and then the properties associated with the product
variant. That's going to be another
id, this time the
Let’s take a shot at implementing this.
We’ll create an input,
const productInput =. Then we'll insert an
id: productID, and then we're also going to have
variant is actually an
array because there are multiple and each of them are a map of their own.
So we’ll put
id: variantId, in that map, and also
price: updatedPrice for this particular edge or product, because we're looping through them all, as outlined above.
Every time we're calculating our
updatedPrice here, it's for one particular product and we have that captured within our
Now we have everything we need to be able to execute this mutation, which is fantastic!
You might also like: How to Build a Shopify App: The Complete Guide.
The final step: calling your mutation
The last thing we want to do is to go ahead and call this mutation. Doing so looks something like this:
To call it, we’re going to say
constant mutationData = I'm going to synchronously wait for the response of the GraphQL client (
Then we’re going to make a standard request,
We also want to be able to catch and log any errors that might happen,
Before running that, you might also want to log the stringified version of the
mutationData. The extra parameters help with formatting and keeping things clean by adding some white space around the new lines. The code for that looks like this:
console.log(JSON.stringify(mutationData, undefined, 2))
We’ve followed the
productInput format laid out in the documentation, however it all needs to be nested within a map, where we specify that it is indeed an input. Otherwise there is confusion around that component. So we’ll just add that in like below:
Once you’ve done that, save and hit run. You should expect to see the
for loop going through each one of those
products and making an
update to the
price. This is what your terminal should look like:
Success! It's looping through each of our products, retrieving the values, and then it's making that update. We’re also seeing no errors and getting our
productId back, so that’s fantastic.
Where do we go from here?
Now what are we missing? So far, we don't know how much rate limit we still have available when making these requests. We have no idea when we might run into an error. So stay tuned for the next post in this series, where you’ll learn how to capture information, optimize, and responsibly use your app's rate limit.
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