docs
  1. SCAYLE Resource Center
  2. Onboarding Guide
  3. Onboarding: frontend
  4. Get Single Product By ID

Get Single Product By ID

In this section, we'll dive into the endpoints required for building a product detail page that showcases your product in the best possible way. To find more information on how to use the Storefront API for fetching products, click here.

Fetch a single product using its ID

bapiClient.products.getById

What is this endpoint for?

The bapiClient.products.getById returns a single product, or null if no product was found. The with parameter defines which information about the product should be returned. Always pass the campaignKey if available, as it may alter the price of the product.

Dev-to-Dev Hint

The SFC provides a function called useProduct(...) that wraps the Storefront API function. If you don’t want any caching or a new Storefront API feature is not provided by SFC but you need it anyway, you can implement your own wrapper, using the RPC wrapper, like this:

export const getProductById: RpcHandler<
  {
    id: number
    with: ProductWith
    ttl?: number
  },
  Product
> = async function getProductById(
  options,
  { bapiClient, cached, campaignKey }
) {
  return await cached(bapiClient.products.getById, {
    ttl: options.ttl ?? 60 * 60,
  })(options.id, {
    with: options.with,
    campaignKey,
  })
}

This custom RPC method provides developers with the flexibility to set a custom TTL for fetching a product by ID. The composable useStockResolver helps update the stock of a product on a specific PDP, preventing purchase if the stock is 0. It utilizes the custom RPC method from above to fetch a product on the client-side, with no caching in between, to fetch the most up-to-date stock.

If a product is not returned and you can’t figure out why, consider manually requesting what the Storefront API returns:

.../v1/products/191?includeSoldOut=true&shopId=3501&with=variants,attributes,advancedAttributes,siblings

The with parameter should be stored globally within the project to ensure any new product attribute is resolved consistently across the project. This is partially implemented in the demo shop:

export const WISHLIST_WITH = {
  items: {
    product: {
      attributes: {
        withKey: ['color', 'brand', 'name'],
      },
      categories: 'all',
      variants: {
        attributes: {
          withKey: ['price', 'size'],
        },
        lowestPriorPrice: true,
      },
      ...

Example

Below is an example of a Product Detail Page (PDP) that attempts to fetch a product by its ID. If the product can't be found, the user is redirected to a 404 error page:

    const {
      data,
      fetch,
      fetching,
    } = useProduct(`product-${id.value}`)
    
    onFetchAsync(async () => {
       await fetch({
          id: id.value,
          with: {
              attributes: {
                withKey: [
                  'color',
                  'brand',
                  'name'
                ],
              },
              advancedAttributes: {
                withKey: ['materialCompositionTextile', 'productDescription'],
              },
              variants: {
                attributes: {
                  withKey: ['price', 'size'],
                },
                lowestPriorPrice: true,
              },
              images: {
                attributes: {
                  withKey: ['imageType', 'imageView', 'imageBackground'],
                },
              },
              categories: 'all',
              siblings: {
                images: {
                  attributes: {
                    withKey: ['imageType', 'imageView', 'imageBackground'],
                  },
                },
                attributes: {
                  withKey: ['color', 'name', 'brand'],
                },
              },
              priceRange: true,
              lowestPriorPrice: true,
            },
       })
       if (!data.value) return redirectTo404()
    })

Next Steps

Get items from the basket.