Why has Shopify storefront API stopped working on my next.js website?

Tom_Wicks
Visitor
1 0 1

I have a shopify website build on Next.js using the Shopify Storefront API. I built the site 2 years ago and it was working perfectly until it stopped building recently. We haven't changed anything in the codebase, or store. 

 

Now when I go to run the store locally or build the shop on vercel I get a new error 

CleanShot 2023-09-27 at 11.16.28@2x.png

TypeError: Cannot read properties of undefined (reading 'collectionByHandle')


Why has this stopped working and how do i go about troubleshooting the issue?  


Here is the Shopify JS file. 

lib/Shopify.js

const domain = process.env.SHOPIFY_STORE_DOMAIN
const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESSTOKEN

async function ShopifyData(query) {
  const URL = `https://${domain}/api/2021-07/graphql.json`

  const options = {
    endpoint: URL,
    method: "POST",
    headers: {
      "X-Shopify-Storefront-Access-Token": storefrontAccessToken,
      "Accept": "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query })
  }

  try {
    const data = await fetch(URL, options).then(response => {
      return response.json()
    })

    return data
  } catch (error) {
    throw new Error("Products not fetched")
  }
}

export async function getProductsInCollection() {
  const query = `
  {
    collectionByHandle(handle: "frontpage") {
      title
      products(first: 60) {
        edges {
          node {
            id
            title
            productType
            handle
            metafields(first: 2) {
              edges {
                  node {
                      namespace
                      key
                      value
                  }
              }
          }
            priceRange {
              minVariantPrice {
                amount
              }
            }
            options {
              name
              values
              id
            }
            variants(first: 1) {
              edges {
                node {
                  selectedOptions {
                    name
                    value
                  }
                  image {
                    originalSrc
                    altText
                    height
                    width
                  }
                  availableForSale
                  title
                  id
                }
              }
            }
            images(first: 2) {
              edges {
                node {
                  originalSrc
                  altText
                  height
                  width
                }
              }
            }
          }
        }
      }
    }
  }`

  const response = await ShopifyData(query);
  const allProducts = response.data.collectionByHandle.products.edges
    ? response.data.collectionByHandle.products.edges
    : [];
  return allProducts;
}

export async function filter(type) {
  let filtredProducts = await getProductsInCollection();
  return filtredProducts.filter((product) => product.node.productType === type);
}

export async function getAllProducts() {
  const query = 
  `{
    products(first: 250) {
      edges {
        node {
          handle
          id
        }
      }
    }
  }`

  const response = await ShopifyData(query)

  const slugs = response.data.products.edges ? response.data.products.edges : []

  return slugs
}

export async function getProductTypes() {
  const query = 
  `{
    shop {
      products(first:250, query:"-product_type:''") {
        edges {
            node {
              productType
          }
        }
      }
    }
  }`

  const response = await ShopifyData(query)

  // console.log(response)

  const productTypes = response.data.shop.products ? response.data.shop.products.edges : []

  return productTypes
}

export async function getProduct(handle) {
  const query = `
  {
    productByHandle(handle: "${handle}") {
    	collections(first: 1) {
      	edges {
          node {
            products(first: 5) {
              edges {
                node {
                  priceRange {
                    minVariantPrice {
                      amount
                    }
                  }
                  handle
                  title
                  id
                  images(first: 5) {
                    edges {
                      node {
                        originalSrc
                        altText
                        height
                        width
                      }
                    }
                  }
                }
              }
            }
          }
        }
    	}
      id
      title
      handle
      description
      metafields(first: 2) {
        edges {
            node {
                namespace
                key
                value
            }
        }
      }
      images(first: 50) {
        edges {
          node {
            originalSrc
            altText
          }
        }
      }
      options {
        name
        values
        id
      }
      variants(first: 1) {
        edges {
          node {
            selectedOptions {
              name
              value
            }
            image {
              originalSrc
              altText
            }
            title
            quantityAvailable
            availableForSale
            id
            priceV2 {
              amount
            }
          }
        }
      }
    }
  }`

  const response = await ShopifyData(query)

  const product = response.data.productByHandle ? response.data.productByHandle : []

  return product
}

export async function createCheckout(id, quantity) {
  const query = `
    mutation {
      checkoutCreate(input: {
        lineItems: [{ variantId: "${id}", quantity: ${quantity}}]
      }) {
        checkout {
          id
          webUrl
        }
      }
    }`

  const response = await ShopifyData(query)

  const checkout = response.data.checkoutCreate.checkout ? response.data.checkoutCreate.checkout : []

  return checkout
}

export async function updateCheckout(id, lineItems) {
  const lineItemsObject = lineItems.map(item => {
    return `{
      variantId: "${item.id}",
      quantity:  ${item.variantQuantity}
    }`
  })

  const query = `
  mutation {
    checkoutLineItemsReplace(lineItems: [${lineItemsObject}], checkoutId: "${id}") {
      checkout {
        id
        webUrl
        lineItems(first: 25) {
          edges {
            node {
              id
              title
              quantity
            }
          }
        }
      }
    }
  }`

  const response = await ShopifyData(query)

  const checkout = response.data.checkoutLineItemsReplace.checkout ? response.data.checkoutLineItemsReplace.checkout : []

  return checkout
}




export async function recursiveCatalog(cursor = '', initialRequest = true) {
  try {
  let data;

  if (cursor !== '') {
    const query = `{
      products(after: "${cursor}", first: 250) {
        edges {
          cursor
          node {
            id
            handle
          }
        }
        pageInfo {
          hasNextPage
        }
      }
    }`;

    const response = await ShopifyData(query);
    data = response.data.products.edges ? response.data.products.edges : [];

    if (response.data.products.pageInfo.hasNextPage) {
      const num = response.data.products.edges.length;
      const cursor = response.data.products.edges[num - 1].cursor;
      console.log('Cursor: ', cursor);

      return data.concat(await recursiveCatalog(cursor));
    } else {
      return data;
    }
  } else {
    const query = `{
      products(first: 250) {
        edges {
          cursor
          node {
            id
            handle
          }
        }
        pageInfo {
          hasNextPage
        }
      }
    }
    `;

    const response = await ShopifyData(query);
    data = response.data.products.edges ? response.data.products.edges : [];

    if (response.data.products.pageInfo.hasNextPage) {
      const num = response.data.products.edges.length;
      const cursor = response.data.products.edges[num - 1].cursor;

      return data.concat(await recursiveCatalog(cursor));
    } else {
      return data;
    }
  }
} catch (error) {
  // Log the error for debugging purposes
  console.error(error);
}
}

 

Replies 2 (2)

owencs
Shopify Partner
3 0 1

Did you ever figure out the issue? 

Ole_
Shopify Partner
41 8 17

Hi Tom,

 

you are using the 2023-07 API version. In this version products.images is deprecated. This is why collectionByHandle fails and returns undefined.

 

The correct way to get the images looks like this:

{
  product(id: <YOUR_ID>) {
    id
    media(first:10) {
      edges {
        node {
          ... on MediaImage {
            image {
              url
            }
          }
        }
      }  
    }
  }
}

In this case I am querying a product by id, but this applies to all queries that want to fetch the image urls from products.

If you find my suggestions helpful, kindly express your feedback by liking or marking them as a solution.

visionz.de