This is a complimentary blog post to a video from theShopifyDevs YouTube channel.在本文中,查克•Kosman发射工程师at Shopify Plus, walks you through an introduction of using GraphQL with Shopify. We cover:
- What GraphQL is
- What tools you can use to get up and running with GraphQL
- A tutorial of making GraphQL requests against a client’s store
What is GraphQL?
Let's start by answering the question, what is GraphQL? If you were to go toGraphQL.org,你会发现这句话吧。GraphQLis described as, “A query language for APIs and a runtime for fulfilling those queries with your existing data.”
"GraphQL is described as, 'A query language for APIs and a runtime for fulfilling those queries with your existing data.'"
Query languages are expressive, highly structured ways to ask for data, and you might be familiar with them in the context of databases.
Here, we're talking about using query languages for an API. If we were to translate this into a more functional definition, you'd end up with something like this: “GraphQL is an expressive, structured way to ask for data from another application and the underlying system to fetch that data.”
You're probably familiar with RESTful APIs as a way to ask for data from another application. But GraphQL is really being hailed as the better REST. REST solved a lot of problems of its predecessors, but GraphQL is specifically designed to address some of the shortcomings of REST when it comes to modern applications. One of the principal problems with REST in modern applications is that they overfetch or underfetch. This means that in a single request, they either get too much data or they don't get enough.
Let’s use a restaurant, something that's long been used as an analogy for APIs, to explore these concepts a little further.
Build for the world’s entrepreneurs
Want to see more videos just like this? Subscribe to the ShopifyDevs YouTube channel. Get development inspiration, useful tips, and practical takeaways.
SubscribeThe ice cream analogy: exploring concepts relating to APIs
I'm going to use an ice cream shop as my restaurant here and I'm going to start with overfetching.
On Shopify, if I wanted to know something about an order, I would have to use this end point on the admin REST API, and when I plug in an order ID to it, I get everything I could ever want to know about a single order.
In terms of a restaurant or an ice cream shop specifically, this might be an ice cream truck that only has preconfigured sundaes on the menu that contain ingredients that you don't necessarily want and there's no combination that you really do want. The restaurant has put all of this time and effort into putting the toppings on and arranging things as they specified that they would. But, if there's something that your client doesn't like or need, then it's on you to remove those. This can be quite inefficient for both parties.
In contrast, underfetching is when you don't get enough data from a single request. This often comes up when you're looking for deeply nested data.
Here's an example in Shopify where I went to get at the metafields of a certain set of products. I first start by issuing aGET
request to all products. But that's not all the data that I really need.
Then I had to go use a different endpoint, plug in the IDs, and then finally get to the metafields that I want. You may have heard this characterized as then+1
problem. I issued one request to get the entire list of products and then I have to issuen
number of requests to get at each resource that I'm interested in at the end. So in terms of our ice cream shop analogy, this might be something like where I get some ice cream and each time I want a topping, I have to pass the ice cream back and forth and I can only get one topic at a time.
Very inefficient, very inflexible.
You might also like:How to Get More App Downloads in the Shopify App Store.
Enter GraphQL. You supply the query language data that you would like along with your request and you get back only the data that you ask for. What's interesting here is you'll notice that I'm using aPOST
request to this end point on theadmin/API/GraphQL.json
, and along with it I'm supplying a body of this nested structure of data. This particular nested structure of data is a pseudocode example of asking for some fields on products by a particular product ID.
So in this case, let's say I only wanted to examine thetitle
,handle
, and thenvariants
字段属于职业ducts that I might be interested in. I could populate them in the...
as shown below. What I get back ends up being only the data that I asked for.
In the context of our ice cream shop analogy, I would go up to the counter, I specify exactly what flavors and toppings I want, and I get exactly that in one efficient, flexible request.
Because I specify exactly what data I want in each request, it's clear to both the server, that which is filling the query, and the client, myself, my colleagues, and the rest of the application, what data is being used. This is very advantageous for clarity and moving fast. It enables rapid front end iteration because there's only one single endpoint. I don't have to juggle a bunch of different endpoints as a front end developer, and it's how I structure my request that dictates what data I get back, not what endpoints I have to call in sequence.
Lastly, you might be wondering, well, if there's only one endpoint, how do I know what I can even ask for?
This is really the heart beat of GraphQL, this transparent documentation of its capabilities through what's called a schema. We specifically call ita strongly-typed schema, meaning that the patterns of data that you get back are defined by underlying types. And so it's very clear, even as you're typing or formatting your request if you're making an error or not.
Ultimately, all of these things lead to a more efficient, powerful, and flexible successor to REST.
Tools to start making GraphQL requests with Shopify
Now that we know a little bit about what GraphQL is and how it compares to REST, let's start talking about the tools that you can use to start making GraphQL requests on Shopify.
It could be as simple as acURL
request, but you'd miss out on this strongly-typed schema, one of the most powerful features of GraphQL. However, we can get that using something called the GraphiQL IDE or Integrated Development Environment. We have an implementation of this for both the GraphQL admin API and the storefront API. We'll talk about the distinction between those in a moment, but we're going to stick with the admin API implementation.
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 upWhat you’ll need to get started
There is a piece of documentation called theShopify Admin API GraphiQL Explorer.You can actually start playing around with it as read only right here in the documentation, but if you'd like to follow along in this tutorial, I'm going to suggest that youinstall Shopify's GraphiQL app.
You'll need a store to install this on, so if you don't already have a partner development store or a trial store, no worries. There's great documentation on exactly how to do this. If you need to get a store up and running on which to install it, there's another piece of documentation calledMake Your First GraphQL Requestin our Shopify dev tutorials.
And right at the top, there's only two steps that you need to follow of these three. One is creating a partner account. These are what folks in our ecosystem use to make merchant solutions. It's totally free.
With that partner account, you will create a development store or log into an existing one if you have one. We won't need this last part for our tutorials using GraphiQL, but you could optionally follow along here if you prefer to work with a standalone HTTP client. And we'll see what that looks like as well in a moment.
So if you don't have a store, get one, and I highly suggest populating some test data so that when you go to make queries, you're going to get some meaningful data back. You could stick with products and variants, but you can go as far as products, customers, and orders if you so desire. Those are kind of the big three.
The Shopify GraphQL Integrated Development Environment (IDE)
Anyway, I'm going to go back to this Shopify Admin API GraphiQL Explorer and I'm going to install it on a store that I already have set up. I'm going to say install Shopify's GraphiQL app following this link. I happen to have a store already,getting-started-with-graphql.myshopify.com
, and I'm going to select that from my browser's autocomplete here.
And this is where you're going to define what scopes this app has access to. If you know the store isn't being used for production, you can safely select all of the scopes. If this is already a production store, I highly suggest you use a development or test store instead, and be very careful, because this app can read and write. So be cautious in selecting your selected scopes.
For this tutorial, you'll really only need products in terms of what I'm going to show, so I'm going to saySelect Allbecause it makes things easier and I'm going to sayInstall.It's going to prompt me to say, “Do you want to grant this app all of these different scopes?” I'm going to sayYes.
Once it's finished installing, you'll see an interface like this, a left hand column with this shop name JSON formatted thing and this right-hand column that's blank for now. We'll be using this for the tutorial, but we'll flip back to other methods of working with GraphQL just for the time being.
You might also like:Faster Retrieval of Shopify Metafields with GraphQL.
The standalone HTTP client
You could also use, as I mentioned, a standalone HTTP client. The reason that we're using the GraphiQL IDE for this tutorial is we don't have to specify the endpoint. Fortunately, there's only one in GraphQL, that's one of its wonderful advantages.
But we don't also have to set up the headers either. I'll show you what those headers look like if this is your preferred method of working. You’ll need two headers. You'll need to spin up a private app and you'll need that app's password to pass in as the authentication token under this header name. You’ll also need to specify the content type asapplication/JSON
.
There is anapplication/GraphQL
that some folks get confused about. There are subtle differences and you'll usually want to useapplication/JSON
when working with a standalone HTTP client. If it doesn't work, switch toapplication/GraphQL
.If you need any more guidance on this, you forgot where the slide was, or you want to read this full-on, refer back to thatMake Your FirstGraphQL Requestpiece of documentation. They cover using GraphiQL and in addition to that, they cover using a standalone HTTP client.
There's actually a really awesome blog post for a full tutorial onsetting up one called insomnia.And there's a kit that comes with some preloaded queries that you can start using to get up and running right away. The headers that you'll need and some sample requests are detailed throughout this document. So this is an excellent resource to come back to after this tutorial.
We're going to walk through some elements of this, as well. Last but not least, if you start working at scale, the GraphQL IDE is not going to work for you, this is really just kind of a way to test things. And you wouldn't use a HTTP client to do things in production either, you'd build on a full-on app.
Working at scale: building with GraphQL client libraries
当你去做一个全面的应用,我强烈recommend looking into GraphQL client libraries. Because of the predictability that comes out of this strongly-typed schema of GraphQL, you can layer a lot of developer tools on top of that for rapid and awesome development. You may have heard of Apollo or Relay as popular client libraries, but there are others and it depends on what languages, frameworks, and platforms you're targeting.
"Because of the predictability that comes out of this strongly-typed schema of GraphQL, you can layer a lot of developer tools on top of that for rapid and awesome development."
I briefly touched on that there are two different APIs that you might work with using GraphQL. They are the admin APIs, both REST and GraphQL. Both are used for developing apps and integrations for the Shopify admin. It’s like extending the back office of Shopify, if you want to think of it that way. However the storefront API is for customer-facing purchase experiences, a very different purpose.
And we have software development kits or SDKs to target the web, Android, iOS, and even in-game experiences via Unity. In addition to the fact that GraphQL is the only one available
for storefront-to-storefront API, there are clearly advantages of using GraphQL over REST. In fact, there are certain things you can do using the GraphQL flavor of the admin API that you can't do on the REST API.
In other words, Shopify is really betting on GraphQL. We see the benefits of GraphQL in comparison to RESTful APIs.
What you can accomplish with GraphQL admin APIs
In the past, and continuing now and in the future, there will be certain things that you should expect you can only do on the GraphQL admin API. Some of those listed out here in chronological order of their release:
- There's a way to bulk adjust inventory on the GraphQL admin API that is many, many more times efficient than the REST API could ever be on the same operation. This is really good forinventory managementat scale.
- The translations API is GraphQL only.
- Product media, so being able to not just do images but videos and 3D models, is GraphQL.
- Order editing, a long requested feature, is GraphQL only on the admin API.
- As of this post, the duties and taxes APIs and developer preview are GraphQL as well.
你应该d expect that there absolutely will be more features that will be only on GraphQL in the future. You can check these out on ourdeveloper changelogif you want to stay up to date with our Shopify API releases.
You might also like:GraphQLvs REST: How One Shopify Partner Increased Performance and Reliability.
Applying your knowledge: using GraphQL with Shopify
Now that we've got our tools in place, let's start making requests to our client’s Shopify store using the GraphiQL IDE. I'm going to flip over to my store here in the browser, right where I left off with the GraphiQL IDE installation and you should see something that looks a little bit like this:
The first thing I'm going to do here is actually going to format this a little bit more nicely, in order to make it look a little bit more like how folks tend to work with this:
{
shop {
name
}
}
You can see that the query language of GraphQL, even just from this starter example here, looks a little bit like a nested structure of JSON. I'm just going to pressPlay.This is how I'm going to say, “Send a request”, essentially to get at what I need. So I’m going to clickExecute query, and what I get back is JSON with two properties.
One is calleddata
, and you'll notice that the structure of the data that comes back exactly mirrors the request format that I put in. So I have ashop
property, and the value of that property is an object, and that object has one key called"name"
that I've requested and it so happens that my shop name here is"Getting Started with GraphQL"
.
This extension is actually talking to us about how much this query costs. If you've worked with Shopify's APIs before, particularly the REST API, you know that there is a cap on how many requests you can issue at any given time and how fast those requests leak from this bucket. We call it a leaky bucket model.
GraphQLdoes have the same limitations, but it is through the cost of the query itself, not the call. The end result of this is that GraphQL ends up being way more efficient.
Remember that overfetching example? There's a lot of computation going on in the background of things that you may not necessarily need. GraphQL is computing the cost of what you requested just based on what you requested, so it is massively more efficient. What else can I query for here?
I can pressEnterand start typing any letter, sayC
货币代码。当我这样做时,我得到一个autocomplete of the things that I can query for onshop
.I'll be more specific, they're not just things, we call them fields. A field is just the data that you're interested in.
The reason that GraphiQL can do this is because of this strongly-typed schema. It knows the capabilities of the API and it knows exactly what fields belong on which nodes. We'll talk about nodes in just a second here.
If I were to say, tell me about the currency code of the shop and I pressplayagain, there I have currency, I have to set up the store in USD.
Beyond just typing in autocomplete, how do I know what the capabilities of this API are? What is this schema that we've been talking about that's strongly-typed? In this GraphiQL IDE and in standalone HTTP clients that have good GraphQL capabilities, you'll see something that either looks like docs, in this particular instance, or schema.
This tells me exactly what I can do, and it starts out a little bit mysterious at first if you're new to GraphQL.
There's two things I can do at the most basic level. I can:
- Read data, which is a query.
- I can make a mutation. A mutation is for writing operations.
Comparing this to CRUD architectures in REST, reading is all that a query does. Mutations are everything else; that's creating, updating, and deleting.
Querying data with GraphQL
Now, if I omit the wordquery
, I'm implicitly making a query. So if I actually type inquery
here and pressplay, I'll get the same exact thing. We're making queries to start and we'll move on to mutations in a bit.
The next question becomes, “How do I know thatshop
is something that I can get from theQueryRoot
?” In other words, my entry point into querying for data. That's theQueryRoot
.
I can explore the schema to get exactly that. A query always returns a type ofQueryRoot
.If I click onQueryRoot
,re's a lot of information here. There's a lot of things I could query, and this is the schema. This is the thing that defines what I can and can'tquery
for. It's in alphabetical order. Let’s scroll all the way down to S forshop
.This is the schema's definition ofshop
.It says, “Returns ashop
resource corresponding to the access token used in the request.” I haven't actually explicitly supplied an access token, that's kind of the beauty of using GraphiQL.
So, what does this mean when it comes to a schema? What doesshop:shop!
mean?
It means that if I were to query for ashop
field, I will get atype
back as denoted byShop
.That's how I know what fields I can query for underneathShop
.The exclamation point means non-nullable, I have to get something back.
So, how do I know that name and currency code are available onShop
?
If I click on theShop
type, these are all the things that I can get onShop
.If I were to scroll down, there's quite a lot. This is where I got currency code. What does currency code return? It returns a currency code type (CurrencyCode
). What doesname
return?name
返回一个string.
This is the power of GraphQL's strongly-typed schema and the tools that reside on top of it.
I can explore the scheme in real time to see exactly what I can get at. And I know exactly, very predictably what data I can and can't get and what format it's going to be as I explore around. For most purposes, you might useShop
every now and then in production, but you want to start really digging into some of the data entities on the store.
Let’s do an example with products.
You might also like:The Shopify App CLI Tool: Build Apps Faster.
A query example with products
I'm going to structure my query as I go, and compare it to the schema just so
that you can see what's going on. I’ll also take a look at a visualization of how to mentally model these types related to one another in the schema.
I'm going to get rid ofquery
because getting rid of the wordquery
actually implicitly makes a query. Go ahead and get rid of everything, making sure to preserve the curly braces. I'm inQueryRoot
here, so I'm going to probably be interested inproducts
.
OK, soproducts
is a little bit more complicated.
I have the fieldproducts
and then I have this parentheses to sayfirst
,after
,last
,before
,sortKey
, all this stuff. Eventually, it says I get returned a type calledProductConnection
.
There’s a lot of terminology here, so let's start from the ground up.
If I useproducts
here and autocomplete already knowing thatproducts
is something I can query for on theQueryRoot
.I'm going to open the curly braces again. It's expecting something else here. Well, what do we want onproducts
?
Let's say, I wanted theirtitle
.Oh, weird. As soon as I typedtitle
, that's not something that's coming up. So, what's going on here?
If I pressplay,fields
title doesn't exist on product connection, thank you, strongly-typed schema. That’s awesome. But, it's something onProductConnection!
callededges
pops up, and I get an array of[ProductEdge!]!
s. So, let’s just start with that,edges
.OK, that's going to have some fields on it, so I'll click on[ProductEdge!]!
to see what exactly that does.
There’s acursor
and anode
and it seems likenode
返回一个product
type, so that's probably what I want. And then onnode
,se are probably things you're more familiar with onproduct
types. Let’s say I just want theID
and thetitle
.
I'll pressplayand I'm going to get an error:you must provide one of first or last
.
OK, so what does that mean? It's expecting something onproducts
to qualifyfirst
orlast
.Again, with strongly-typed schema, it's very informative.
What isfirst
orlast
? Just like in REST, you can't get every single list product just by issuing the get all products endpoint, it's actually paginated. We use cursor based pagination at the recommendation of the GraphQL specification.
That aside, let's take a look at how to do this. To supply what's called an argument, so a qualifier on a request, you must open parentheses. It's actually already saying, “Here are the different ones that you can do”. I'm just going to do the simplest possible one of saying I want thefirst
.What is thefirst
? Well, I have to provide an integer. So I'm going to say I want the first 10 products. We’ll ignore theedges
andnode
thing in the middle for now, but we'll get into it in just a moment.
If I pressplay, now we've got really interesting stuff. We havedata
, which returns an object with theproducts
property. This, in turn, returns an object ofedges
, which is an array of objects, each containing anode
object and eventually, the data that I requested. So I have just theID
and thetitle
in each product.
How much does that cost? It costs 12 points.
What does that mean? Well, in GraphQL you have a maximum bucket size of 1,000 points and that replenishes at 50 points per second.
Contrast this to 40 API REST calls that you can have in a bucket on the RESTful API that regenerates at two calls per second. The net result: GraphQL is way more efficient than REST, even without all the other goodies on top of this.
GraphQL: exploring the terminology
Let’s come back to this weirdedges
andnode
terminology. What is that? When we talk about GraphQL, we're talking about, for the sake of the API, modeling your data as a graph, a visual representation of how different pieces of data connect to one another.
So, let's talk a little bit about GraphQL terminology and how it's going to help you navigate your work.
As soon as you start working with lists of things, you're going to run intoedges
andnode
s all the time. Let’s just back up a step and talk about what those are.
This is essentially a stripped down version of the query that I just wrote: both the code over here and a visual representation of what's going on. I'm entering at theQueryRoot
and attaching thatQueryRoot
to our products. Those products have properties on them. I'm querying fortitle
.In graph theory, these individual entities are what we callnodes
and we call the relationships between entitiesedges
.
This is why when I go at the root level and I want to know aboutproducts
, I have to say, “Get me all of the relationships toproducts
.” I'm saying get me all of theedges
.Then, at the ends of thoseedges
, tell me about the entities at the ends of thoseedges
.Those arenode
s.
You'll see all the time when you start working with plural requests, such as getting a list of things, you'll get in the habit of sayingedges
,node
, and then getting the thing at the end.
Let’s take this a step further: deeply nested queries. We talked about underfetching before, so let's say I want all of the variants on these first 10 products as well. It just so happens that if I type the letterV
,variants
is something on here. There's a list ofvariants
that correspond toproducts
.I know that I'm going to have to sayfirst
, so I'll just say 10 again arbitrarily.
That returns a list ofedges
, and at the end of thoseedges
,re's the variantnode
.Let’s say you want theID
and thetitle
of those variants. I'll pressplayagain. Awesome. Again, the structure of the data that comes back exactly mirrors the structure of the data how I requested it.
So, I have data and thenproducts
comes back as an object andedges
as an array. Each node has theID
in the title as requested and all of the variant information, but only what I requested: just theID
andtitle
of each variant. I could extend this withprice
and so on by looking at the schema to see what data is available on variants.
Just flipping back to this mental model, all that I've done is I've taken the same request and I've extended it a little bit.
Products have a relationship to variants and product nodes have a relationship to variant nodes. Any time there's a relationship in a graph model, we call that an edge. That’s the line between the two. Each product has some variants at the end of it. In this case, I'm only saying two, just for the sake of making the diagram a little bit shorter.
To go back to our visual depiction of what we did here by adding variants under products, we started here with getting the product nodes attached to thisQueryRoot
.
We know that there's a relationship betweenvariants
andproducts
.So inside of this product node, there is avariants
connection. And all that a connection means in GraphQL is a list ofedges
.Anedge
is a relationship between twonodes
.At the end of thatedge
is thenode
that has the fields in question that I want to get here.
Theseproduct nodes
are related tovariant nodes
.The line represents anedge
and thosevariants
in turn have titles on them. So any time you see the word connections, just keep in mind you'll need to think ofedges
andnodes
to abide by this underlying model for the API of what's actually going on.
You might also like:Developing Your First Shopify App: 4 Mistakes to Avoid.
Writing data with mutations in GraphQL
So, we've covered querying data. That's half of the equation. We also want to be able to write data.
This was a query, implicitly, if you leave out the wordquery
here right at the top, it's a query. We actually need to write the wordmutation
.
If I back up through the schema all the way to the root, I canquery
and I can makemutation
s. Let's investigate what types ofmutation
s I can make.mutation
s, as we covered, cover everything for writing data. That's creating, canceling, updating, deleting.
我们的名字mutation
s in Shopify is we talk about the thing that themutation
is being made on to start and then the actual operation that's taking place there. Without scrolling alphabetically through this, I'm going to type in the letterP
.It knows and you can see there'sproductCreate
,productDelete
, andproductUpdate
.So, I'm going to sayproductCreate
.
I can scroll through this schema on the right hand side alphabetically or I can hover over this with my mouse and then just click on this name down here, and it will quick-jump you to the definition of thismutation
, which is very handy.
Now, what's going on here? This is saying that when you make thismutation
, you'll get aProductCreatePayload
back. There are a couple of arguments that are supplied as part of thismutation
.If you're familiar with the REST API, when you make aproduct
,response is all the information you could ever want about that newly created product.
Just like with queries, I can specify only the data that I want back. I have to sayproduct
first and then the stuff you'd expect, created at,description
,title
, and so forth. More important here are the arguments. This is saying that this product input type is not nullable by the exclamation point. So, I have to provide that.media
is an array of this non-nullableCreateMediaInput
type. However, the array itself is not non-nullable, so I don't have to provide that. In other words, all I need to provide is thisProductInput
.
As with all arguments, I'm going to open a set of parentheses. I'm going to format this as an object. I'm also going to create atitle
on this product called"Awesome Product"
.I'm going to open up thatmutation
to receive theProductCreatePayload
, which has a field on it calledproduct
.Inside of thatproduct
is where I can get all the good stuff. I'm going to say I want theID
and then just to make sure, I'm going to say I want thetitle
.I'll make thismutation
by pressingplayand you'll notice theID
if you've worked with the REST API before.
This is a little bit different, theID
s are not interchangeable. GraphQL has its own set ofID
s to refer tonodes
.Don't try to use theID
s interchangeably and indeed, I get“标题”:“了不起的产品”
back.
去ing further with GraphQL
Congratulations! That's getting up and running with making both queries and mutations on a Shopify store with GraphiQL. So, where do you go from here to expand your knowledge set on GraphQL?
There are many fantastic resources out there on the web for learning about GraphQL. Some of them are published by Shopify and I've called out through this tutorial, notably our tutorial andmaking your first GraphQL request.This is an excellent resource to come back to, especially after watching this tutorial. The mutations and queries that you'll make in that tutorial are a little bit different, but the principles are the same.
"There are many fantastic resources out there on the web for learning about GraphQL."
Shopify'sGraphQLlearning kitis a great place to start if you want to get up and running with a standalone HTTP client. As part of that blog post, there's a discussion of GraphQL as well as a downloadable set of preconfigured insomnia queries and mutations to start working with against a store. You'll just have to populate a private app key.
If you're interested in the storefront API SDKs and how they can make working with the storefront API even faster. You can check out ourStorefront API Tools Library.
I cannot understate how awesome the “how to GraphQL” set of tutorials are. They go much deeper than this particular tutorial does and there are great practical tutorials for working with certain frameworks, libraries, and languages. For example, if you're a React developer and you want to understand React and Apollo together, a very popular client library, there's a step-by-step tutorial on exactly how to do that.
It also never hurts to go to theofficial GraphQL site, which really lays out in very clear language the specification of GraphQL itself, a very helpful resource for moving forward.
Build for the world’s entrepreneurs
Want to see more videos just like this? Subscribe to the ShopifyDevs YouTube channel. Get development inspiration, useful tips, and practical takeaways.
Subscribe