Fetch Shopify API data in Hydrogen
Hydrogen uses Remix loader
functions to handle all queries to the Storefront API, Customer Account API, and third-party data sources.
Loading data efficiently is important to keeping your Hydrogen app fast and performant. Follow these examples and best practices to ensure your Hydrogen storefront is delivering the fastest experience for customers.
Anchor to Query Shopify APIsQuery Shopify APIs
Hydrogen provides built-in API clients for the Storefront API and the Customer Account API.
Anchor to Query the Storefront APIQuery the Storefront API
The following is an example of how the /products/:handle
route can query the Storefront API and then render that product data in a component.
This example demonstrates a simple version of this pattern. However, it can be extended to cover more complex behaviors, including more robust error handling, GraphQL query fragments and directives, deferred loading for non-critical data, server-side caching for non-personalized data, and more.
Query product data from the Storefront API
/app/routes/products.$productHandle.jsx
import {useLoaderData} from '@shopify/remix-oxygen';
// Fetch and return API data with a Remix loader function
export async function loader({params, context}) {
const {handle} = params;
const {storefront} = context;
const {product} = await storefront.query(PRODUCT_QUERY, {
variables: {handle},
});
return {product};
}
// Render the component using data returned by the loader
export default function Product() {
const {product} = useLoaderData();
return (
<h1>{product.title}</h1>
)
}
// Query the product title by its ID
const PRODUCT_QUERY = `#graphql
product(handle: $handle) {
title
}`
import {useLoaderData} from '@shopify/remix-oxygen';
import type { LoaderArgs } from '@shopify/remix-oxygen';
import type { Product } from '@shopify/hydrogen/storefront-api-types';
// Fetch and return API data with a Remix loader function
export async function loader({params, context}: LoaderArgs) {
const {handle} = params;
const {storefront} = context;
const {product} = await storefront.query(PRODUCT_QUERY, {
variables: {handle},
});
return {product};
}
// Render the component using data returned by the loader
export default function Product() {
const {product} = useLoaderData<typeof loader>();
return (
<h1>{product.title}</h1>
)
}
// Query the product title by its ID
const PRODUCT_QUERY = `#graphql
product(handle: $handle) {
title
}
`
Anchor to Query the Customer Account APIQuery the Customer Account API
The following is an example of how the /account/order/:id
route can query the Customer Account API to display information about a single order. This example assumes that a customer is logged in.
Query customer order data from the Customer Account API
app/routes/account.orders.$id.tsx
import {useLoaderData} from '@shopify/remix-oxygen';
// Fetch and return API data with a Remix loader function
export async function loader({params, context}) {
const orderId = atob(params.id);
const {data, errors} = await context.customerAccount.query(
CUSTOMER_ORDER_QUERY,
{
variables: {orderId},
},
);
if ((errors && errors.length) || !(data && data.order)) {
throw new Error('Order not found');
}
return {order: data.order};
}
// Render the component using data returned by the loader
export default function Order() {
const {order} = useLoaderData();
if (order) {
return (
<h1>{order.name}</h1>
)
}
}
// Query the order name by its ID
const CUSTOMER_ORDER_QUERY = `#graphql
query Order($orderId: ID!) {
order(id: $orderId) {
name
}
}`
import {useLoaderData} from '@shopify/remix-oxygen';
import type { LoaderArgs } from '@shopify/remix-oxygen';
// Fetch and return API data with a Remix loader function
export async function loader({params, context}: LoaderArgs) {
const orderId = atob(params.id);
const {data, errors} = await context.customerAccount.query(
CUSTOMER_ORDER_QUERY,
{
variables: {orderId},
},
);
if (errors?.length || !data?.order) {
throw new Error('Order not found');
}
return {order: data.order};
}
// Render the component using data returned by the loader
export default function Order() {
const {order} = useLoaderData();
if (order) {
return (
<h1>{order.name}</h1>
)
}
}
// Query the order name by its ID
const CUSTOMER_ORDER_QUERY = `#graphql
query Order($orderId: ID!) {
order(id: $orderId) {
name
}
}`
Anchor to Caching loaded dataCaching loaded data
Hydrogen caches Storefront API data by default. It also includes a set of utilities to customize caching rules for individual API queries. Consult the Hydrogen caching docs for more details about configuring server-side cache rules, including creating your own custom caching rules.
To avoid storing Personally Identifiable Information (PII) or other sensitive data, the Customer Account API client doesn't cache any requests. Caching this information could lead to unauthorized access or data breaches, compromising user privacy and security.
The following simplified example shows how to cache data for longer when querying for the product title, which is an API resource that typically doesn't change frequently:
Customizing caching in loader functions
/app/routes/products.$productHandle.jsx
import {useLoaderData} from '@shopify/remix-oxygen';
export async function loader({params, context}) {
const {handle} = params;
const {storefront} = context;
const {product} = await storefront.query(PRODUCT_QUERY, {
variables: {handle},
// Pass a `cache` option with your query to customize API request caching.
cache: storefront.CacheLong()
});
return {product};
}
export default function Product() {
const {product} = useLoaderData();
return (
<h1>{product.title}</h1>
)
}
const PRODUCT_QUERY = `#graphql
product(handle: $handle) {
id
title
}`
import {useLoaderData} from '@remix-run/react';
import type { LoaderArgs } from '@shopify/remix-oxygen';
import type { Product } from '@shopify/hydrogen/storefront-api-types';
export async function loader({params, context}: LoaderArgs) {
const {handle} = params;
const {storefront} = context;
const {product} = await storefront.query(PRODUCT_QUERY, {
variables: {handle},
// Pass a `cache` option with your query to customize API request caching.
cache: storefront.CacheLong()
});
return {product};
}
export default function Product() {
const {product} = useLoaderData<typeof loader>();
return (
<h1>{product.title}</h1>
)
}
const PRODUCT_QUERY = `#graphql
product(handle: $handle) {
id
title
}
`
Anchor to Next stepsNext steps
- Learn more about caching Shopify API data with Hydrogen
- Paginate your Hydrogen data queries to work with large product collections
- Explore the Storefront API with Hydrogen’s built-in GraphiQL client