Introduction
If you’re developing a Shopify app, there’s a possibility that eventually, you want to upload images. Luckily, Shopify provides many ways to upload images into Shopify files. There are a few steps to follow.
This document provides a step-by-step guide on how to upload images to Shopify files using the Shopify GraphQL API. This article acts as supplementary information to this guide.
Step By Step Process
This guide assumes that you already have the following:
- Have the
Shopify CLI
installed - Have a Shopify app running
- Have experience using the Shopify GraphQL API
- Have some UI ready for the user to interact with to upload files
Step One
First use the stagedUploadsCreate
mutation. As per the Shopify docs, you need to send the following information:
fileSize
– The size of the file in bytesfilename
– The name of the file (with the extension)mimeType
– The file’s MIME typeresource
– The file’s Shopify resource type. Here we will useIMAGE
.httpMethod
– The HTTP method to be used. This is not required, but it is highly suggested to include it as this as this will return different things forPOST
andPUT
.
Once you’ve successfully made your request, it will send back stagedTargets
. (This is an array of the StagedMediaUploadTarget
object since Shopify allows for multi-file uploading). These objects will contain the following fields:
parameters
– These parameters resemble authentication headers and you need them to authenticate the following request to upload the file.resourceUrl
– This is the URL that will contain your file. You will need this for another mutation.url
– The URL you will need to make your next post request. (This is usually where things get uploaded to. In our case it was Shopify’s Google Cloud Storage).
Your request should look something like this:
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
stagedUploadsCreate(input: $input) {
stagedTargets {
resourceUrl
url
parameters {
name
value
}
}
userErrors {
field
message
}
}
}
GraphQLAnd your variables should resemble the following:
input: [
{
resource: "IMAGE",
filename: "Name.png",
mimeType: "image/png",
fileSize: "54422",
httpMethod: "POST",
},
],
}
GraphQLYou may also want to pad the file size and make it a little bigger than the actual file size. Please take note that Shopify also has a 20mb limit.
Step Two
Make a POST
request to the url
in step 1. You can also make a PUT
request, but that is for Images only while POST
accepts all media types. Make sure your HTTP method matches the one you declared in step one.
You can make a FormData
and append the file that you are sending. It should look something like this:
// Make a new formdata
const formData = new FormData();
// Get the URL from the stagedTarget object.
const url = stagedTarget.url;
// Since you are only uploading one file, there is only one stagedTarget object. Fet all the parameters, loop through them and append them to the formData.
stagedTarget.parameters.forEach(({name, value}) => {
formData.append(name, value);
});
// lastly, append the file
formData.append('file', file);
// Put the formData in the body of the request
const response = await fetch(url, {
method: 'POST',
body: formData,
});
JavaScriptThere should now be an image in the resourceUrl
if you visit it! This link is only temporary, however, and the file will be deleted after a period of time. In order to use it, we now need to upload it to our Shopify files.
Potential Errors
If you find yourself running into the Cannot create buckets using a POST
error, it may be because you appended the file first before the parameters.
While most of the time, with anything with a key-value pair, the order doesn’t necessarily matter. However, in this case, it made sense that the staged target parameters would come first before the file, because the bucket/resource would not want to host some random huge file without accepting the necessary information.
One key takeaway we can make here is to just follow the order set in examples/tutorials.
Content-Type
Another tip here is that you may be tempted to set the content-type header yourself. This is because when you send the FormData, there will be a boundary in your payload. This boundary becomes automatically set and generated after you make this request.
Step Three
Now we need to use the fileCreate
mutation. The fileCreate mutation accepts an array of files that have the following parameters:
alt
– This is the alt text for the file.contentType
– The content type for the image. Here we will useIMAGE
.originalSource
– This is theresourceUrl
we got from step one. Alternatively, you can use any external URL if you are uploading an image and not other types of media.
Your mutation can look something like this:
mutation fileCreate($files: [FileCreateInput!]!) {
fileCreate(files: $files) {
files {
fileStatus
... on MediaImage {
id
}
}
userErrors {
field
message
}
}
}
GraphQLWhile your variables can look something like this:
files: [
{
alt: "picture of a dog",
contentType: "IMAGE",
originalSource: "temp-storage-url.com/tempURL",
},
],
}
GraphQLStep Four
When you use the fileCreate
mutation, sometimes it doesn’t actually return the image right away. It may even return a null image. This is because of additional processing done by Shopify to your media. At the time of writing this guide, there is no webhook subscription topic that notifies us if the uploaded media is ready.
However, it does reliably return the id
of the image or file you just uploaded, so we can actually use GraphQL to poll for the image.
Your mutation should look something like this:
query getFileByID($id: ID!) {
node(id: $id) {
... on MediaImage {
id
image {
url
}
}
}
}
GraphQLYou can poll this function, but it may be wise to put a delay between attempts so you do not get rate limited. If you plan on uploading videos, you may want to set a longer delay.
Once you get the URL of the image from your Shopify files, you can now successfully use it!
Conclusion
Congratulations, you can now upload images to Shopify! If you enjoyed this post, please feel free to check out the other articles on this blog.
Happy coding!