focused female employee reading information on computer in office

How To Upload Images to Shopify Files Using the Shopify GraphQL API

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:

  1. Have the Shopify CLI installed
  2. Have a Shopify app running
  3. Have experience using the Shopify GraphQL API
  4. 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 bytes
  • filename – The name of the file (with the extension)
  • mimeType – The file’s MIME type
  • resource – The file’s Shopify resource type. Here we will use IMAGE.
  • 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 for POST and PUT.

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:

  1. parameters – These parameters resemble authentication headers and you need them to authenticate the following request to upload the file.
  2. resourceUrl – This is the URL that will contain your file. You will need this for another mutation.
  3. 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:

GraphQL
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
    stagedUploadsCreate(input: $input) {
      stagedTargets {
        resourceUrl
        url
        parameters {
          name
          value
        }
      }
      userErrors {
        field
        message
      }
    }
  }
GraphQL

And your variables should resemble the following:

GraphQL
input: [
            {
              resource: "IMAGE",
              filename: "Name.png",
              mimeType: "image/png",
              fileSize: "54422",
              httpMethod: "POST",
            },
          ],
        }
GraphQL

You 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:

JavaScript
// 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,
});
JavaScript

There 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 use IMAGE.
  • originalSource – This is the resourceUrl 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:

GraphQL
mutation fileCreate($files: [FileCreateInput!]!) {
  fileCreate(files: $files) {
    files {
      fileStatus
      ... on MediaImage {
        id
      }
    }
    userErrors {
      field
      message
    }
  }
}
GraphQL

While your variables can look something like this:

GraphQL
files: [
            {
              alt: "picture of a dog",
              contentType: "IMAGE",
              originalSource: "temp-storage-url.com/tempURL",
            },
          ],
        }
GraphQL

Step 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:

GraphQL
query getFileByID($id: ID!) {
  node(id: $id) {
    ... on MediaImage {
      id
      image {
        url
      }
    }
  }
}
GraphQL

You 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!