What's your biggest current challenge? Have your say in Community Polls along the right column.
Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Getting "Request failed with status code 422" randomly on PUT request to assets

Solved

Getting "Request failed with status code 422" randomly on PUT request to assets

diego_ezfy
Shopify Partner
2970 571 917

Overview

I'm creating an app that needs to store images. Since it's a small amount of images I'm using the own customer's theme for that. This is how I'm currently doing it in Node.JS:

 

      const headers = {
        "X-Shopify-Access-Token": ctx.cookies.get("accessToken"),
      };

      const themesURL = `https://${ctx.cookies.get(
        "shopOrigin",
      )}/admin/api/2020-04/themes.json`;

      const { data: themes } = await axios.get(themesURL, {
        headers,
      });

      const themeId = themes.themes.filter(({ role }) => role === "main")[0].id;

      const assetURL = `https://${ctx.cookies.get(
        "shopOrigin",
      )}/admin/api/2020-04/themes/${themeId}/assets.json`;

      const imageBase64 = item.imageSrc.replace(/^data:image\/\w+;base64,/, "");

      const { data } = await axios.put(
        assetURL,
        {
          asset: {
            key: `assets/highlight-bar-${uuid}.png`,
            attachment: imageBase64,
          },
        },
        {
          headers,
        },
      );

 


Issue

It works just fine, but occasionally it returns a 422 error. I thought it was because I was doing an excessive amount of requests within a short period of time, but I was able to store about 10 images within 30 seconds with no problems. After that I waited for a minute or so and got a 422. I really have no clue what's going on in here since I can't debug it any further.

Expected Behavior

I would like to know why this happens - why does it stop working seemingly out of nowhere? 

I tried handling this sort of error using async await retry with no success. 

Kindly shed some light on this if you can, I've been stuck on this for a while now. 

Thank you!

Accepted Solution (1)

diego_ezfy
Shopify Partner
2970 571 917

This is an accepted solution.

I found the solution.

Taking a look at the Shopify's API response codes I realized there was something wrong with the body of my request. Axios was not returning the proper error message, so I decided to use the Fetch API. 

After doing so I realized it was because my UUID variable was occasionally creating IDs using prohibited characters (e.g. "+", ">", etc) making Shopify reject the request. I fixed it by generating a numeric ID.

This is the final solution in case anyone needs it. I wrapped it in a function to make it easier to be re-utilized.

What it does is simply saving an image into the current user's theme:

const saveImageToTheme = async (ctx) => {
  return new Promise(async (resolve, reject) => {
    try {
      const uuid = new Date().valueOf();
      const accessToken = ctx.cookies.get("accessToken");

      let item = ctx.request.body;

      /* Store image in user's theme */
      const headers = {
        "X-Shopify-Access-Token": accessToken,
      };

      const themesURL = `https://${ctx.cookies.get(
        "shopOrigin",
      )}/admin/api/2020-04/themes.json`;

      const { data: themes } = await axios.get(themesURL, {
        headers,
      });

      const themeId = themes.themes.filter(({ role }) => role === "main")[0].id;

      const assetURL = `https://${ctx.cookies.get(
        "shopOrigin",
      )}/admin/api/2020-04/themes/${themeId}/assets.json`;

      const imageBase64 = item.imageSrc.replace(/^data:image\/\w+;base64,/, "");
      
      const body = JSON.stringify({
        asset: {
          key: `assets/highlight-bar-${uuid}.jpg`,
          attachment: imageBase64,
        },
      });

      let response = await fetch(assetURL, {
        method: "PUT",
        body,
        headers: {
          ...headers,
          Accept: "application/json",
          "Content-Type": "application/json",
        },
      });

      let data = await response.json();

      resolve(data);
    } catch (error) {
      reject(error);
    }
  });
};

 


View solution in original post

Reply 1 (1)

diego_ezfy
Shopify Partner
2970 571 917

This is an accepted solution.

I found the solution.

Taking a look at the Shopify's API response codes I realized there was something wrong with the body of my request. Axios was not returning the proper error message, so I decided to use the Fetch API. 

After doing so I realized it was because my UUID variable was occasionally creating IDs using prohibited characters (e.g. "+", ">", etc) making Shopify reject the request. I fixed it by generating a numeric ID.

This is the final solution in case anyone needs it. I wrapped it in a function to make it easier to be re-utilized.

What it does is simply saving an image into the current user's theme:

const saveImageToTheme = async (ctx) => {
  return new Promise(async (resolve, reject) => {
    try {
      const uuid = new Date().valueOf();
      const accessToken = ctx.cookies.get("accessToken");

      let item = ctx.request.body;

      /* Store image in user's theme */
      const headers = {
        "X-Shopify-Access-Token": accessToken,
      };

      const themesURL = `https://${ctx.cookies.get(
        "shopOrigin",
      )}/admin/api/2020-04/themes.json`;

      const { data: themes } = await axios.get(themesURL, {
        headers,
      });

      const themeId = themes.themes.filter(({ role }) => role === "main")[0].id;

      const assetURL = `https://${ctx.cookies.get(
        "shopOrigin",
      )}/admin/api/2020-04/themes/${themeId}/assets.json`;

      const imageBase64 = item.imageSrc.replace(/^data:image\/\w+;base64,/, "");
      
      const body = JSON.stringify({
        asset: {
          key: `assets/highlight-bar-${uuid}.jpg`,
          attachment: imageBase64,
        },
      });

      let response = await fetch(assetURL, {
        method: "PUT",
        body,
        headers: {
          ...headers,
          Accept: "application/json",
          "Content-Type": "application/json",
        },
      });

      let data = await response.json();

      resolve(data);
    } catch (error) {
      reject(error);
    }
  });
};