Essentials

Storefront API

Using the Shopify Storefront API in Nuxt

The Storefront API is a public API that allows you to access your Shopify store's data, such as products, collections, and customer information. It is designed to be used in client-side applications, such as a Nuxt frontend. To use the Storefront API, you need to obtain a public or private access token.

See the module configuration to see how to set up the module for the Storefront API. If you need help obtaining your access tokens, see the Shopify Setup Guide.

Usage

Once configured, you can use the Storefront API in your Nuxt application via the useStorefront and useAsyncStorefront composables. Depending on where you want to use the API (server or client), you can choose between the two composables.

Client-side

useStorefront

When setting the publicAccessToken for the storefront client in the module configuration, you can use the useStorefront composable in your client-side code. For example, in a page component:

~/app/pages/product.vue
<script setup lang="ts">
const storefront = useStorefront()

const { data: product } = await storefront.request(`#graphql
  query GetProduct($handle: String!) {
    product(handle: $handle) {
      id
      title
      description
    }
  }
`, {
  variables: {
    handle: 'high-top-sneakers',
  }
})
</script>

<template>
  <div v-if="product">
    <h1>{{ product.data.title }}</h1>

    <p>{{ product.data.description }}</p>
  </div>
</template>

You can also wrap use the useStorefront composable in another composable, to build an abstracted data fetching method:

~/composables/useProduct.ts
export const useProduct = (handle: string) => {
  const storefront = useStorefront()

  return storefront.request(`#graphql
    query GetProduct($handle: String!) {
      product(handle: $handle) {
        ...ProductFields
      }
    }
    ${PRODUCT_FRAGMENT}
  `, {
    variables: {
      handle,
    }
  })
}

This way, you can reuse the useProduct composable in multiple places in your application.

By default, each request from the client side is proxied through the Nitro server. This behaviour can be customized by setting proxy: false in the storefront client config.

useAsyncStorefront

You can wrap the useStorefront call with Nuxt's useAsyncData composable to integrate into the hybrid rendering model. To shorten the syntax, the module provides a composable called useAsyncStorefront that automatically does this for us:

~/app/pages/product.vue
<script setup lang="ts">
const handle = 'high-top-sneakers'

const { data: product } = await useAsyncStorefront(`product-${handle}`, `#graphql
  query GetProduct($handle: String!) {
    product(handle: $handle) {
      id
      title
      description
    }
  }
`, {
  variables: {
    handle,
  }
})
</script> 

<template>
  <div v-if="product">
    <h1>{{ product.title }}</h1>

    <p>{{ product.description }}</p>
  </div>
</template>

Server-side

useStorefront

When setting either the publicAccessToken or privateAccessToken for the storefront client in the module configuration, you can use the useStorefront composable in your server-side code. For example, in a server route:

~/server/api/product/[handle].ts
export default defineEventHandler((event) => {
  const handle = getRouterParam(event, 'handle')

  const storefront = useStorefront()

  return storefront.request(`#graphql
    query GetProduct($handle: String!) {
      product(handle: $handle) {
        ...ProductFields
      }
    }
    ${PRODUCT_FRAGMENT}
  `, {
    variables: {
      handle,
    }
  })
})

Using validation

Using Nitro's built-in input validation, you can match the variables of your GraphQL queries before sending them to the API.

For this example we'll use the Zod library, but you can use any validation library you like.

First, install the validation library:

npm install zod

Then, import it and create a schema:

import { z } from 'zod'

const schema = z.object({
  first: z.number({ coerce: true }).min(1),
})
The coerce option is used to convert the string value of the first variable to a number and then match it against the Zod schema. In Nitro, the query variables are always strings, so we convert to a number here before we pass it to the API.

Next, we can use Nitro's built-in getValidatedQuery utility to validate the query variables:

~/server/api/products.ts
import { z } from 'zod'

const schema = z.object({
  first: z.number({ coerce: true }).min(1),
})

export default defineEventHandler(async () => {
  const storefront = useStorefront()
  const variables = await getValidatedQuery(event, schema.parse)

  const query = `#graphql
    query FetchProducts($first: Int) {
      products(first: $first) {
        nodes {
          id
          title
          description
        }
      }
    }
  `

  return storefront.request(query, { variables })
})

Now we can call the API at /api/products with the following variables:

~/pages/your-page.vue
// Requests /api/products?first=1
const response = await useFetch('/api/products', {
    query: {
        first: 1,
    },
})

With the validation, requests will fail before reaching Shopify if the variable first is not a number.