storefront Redirectutility
Queries the Storefront API to see if there is any redirect created for the current route and performs it. Otherwise, it returns the response passed in the parameters. Useful for conditionally redirecting after a 404 response.
Anchor to storefrontRedirect-parametersParameters
- Anchor to optionsoptionsStorefrontRedirectrequired
StorefrontRedirectGeneratedType
Queries the Storefront API to see if there is any redirect created for the current route and performs it. Otherwise, it returns the response passed in the parameters. Useful for conditionally redirecting after a 404 response.
- options
StorefrontRedirect
Promise<Response>
export async function storefrontRedirect(
options: StorefrontRedirect,
): Promise<Response> {
const {
storefront,
request,
noAdminRedirect,
matchQueryParams,
response = new Response('Not Found', {status: 404}),
} = options;
const url = new URL(request.url);
const {pathname, searchParams} = url;
const isSoftNavigation = searchParams.has('_data');
searchParams.delete('redirect');
searchParams.delete('return_to');
searchParams.delete('_data');
const redirectFrom = (
matchQueryParams ? url.toString().replace(url.origin, '') : pathname
).toLowerCase();
if (url.pathname === '/admin' && !noAdminRedirect) {
return createRedirectResponse(
`${storefront.getShopifyDomain()}/admin`,
isSoftNavigation,
searchParams,
matchQueryParams,
);
}
try {
const {urlRedirects} = await storefront.query<{
urlRedirects: UrlRedirectConnection;
}>(REDIRECT_QUERY, {
// The admin doesn't allow redirects to have a
// trailing slash, so strip them all off
variables: {query: 'path:' + redirectFrom.replace(/\/+$/, '')},
});
const location = urlRedirects?.edges?.[0]?.node?.target;
if (location) {
return createRedirectResponse(
location,
isSoftNavigation,
searchParams,
matchQueryParams,
);
}
const redirectTo = getRedirectUrl(request.url);
if (redirectTo) {
return createRedirectResponse(
redirectTo,
isSoftNavigation,
searchParams,
matchQueryParams,
);
}
} catch (error) {
console.error(
`Failed to fetch redirects from Storefront API for route ${redirectFrom}`,
error,
);
}
return response;
}
StorefrontRedirect
- storefront
The [Storefront client](/docs/api/hydrogen/2024-04/utilities/createstorefrontclient) instance
Storefront<I18nBase>
- request
The [MDN Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object that was passed to the `server.ts` request handler.
Request
- response
The [MDN Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object created by `handleRequest`
Response
- noAdminRedirect
By default the `/admin` route is redirected to the Shopify Admin page for the current storefront. Disable this redirect by passing `true`.
boolean
- matchQueryParams
By default, query parameters are not used to match redirects. Set this to `true` if you'd like redirects to be query parameter sensitive
boolean
{
/** The [Storefront client](/docs/api/hydrogen/2024-04/utilities/createstorefrontclient) instance */
storefront: Storefront<I18nBase>;
/** The [MDN Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object that was passed to the `server.ts` request handler. */
request: Request;
/** The [MDN Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object created by `handleRequest` */
response?: Response;
/** By default the `/admin` route is redirected to the Shopify Admin page for the current storefront. Disable this redirect by passing `true`. */
noAdminRedirect?: boolean;
/** By default, query parameters are not used to match redirects. Set this to `true` if you'd like redirects to be query parameter sensitive */
matchQueryParams?: boolean;
}
Storefront
Interface to interact with the Storefront API.
- query
<OverrideReturnType extends unknown = never, RawGqlString extends string = string>(query: RawGqlString, ...options: IsOptionalVariables<StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames, Omit<StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>> extends true ? [(StorefrontCommonExtraParams & Pick<StorefrontQueryOptions, "cache"> & ClientVariables<StorefrontQueries, RawGqlString, AutoAddedVariableNames, "variables", RawGqlString extends never ? { [KeyType in keyof ({ [KeyType in keyof StorefrontQueries[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontQueries[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontQueries[RawGqlString]["variables"], Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>>)]: ({ [KeyType in keyof StorefrontQueries[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontQueries[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontQueries[RawGqlString]["variables"], Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>>)[KeyType]; } : { readonly [variable: string]: unknown; }, Record<"variables", RawGqlString extends never ? { [KeyType in keyof ({ [KeyType in keyof StorefrontQueries[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontQueries[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontQueries[RawGqlString]["variables"], Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>>)]: ({ [KeyType in keyof StorefrontQueries[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontQueries[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontQueries[RawGqlString]["variables"], Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>>)[KeyType]; } : { readonly [variable: string]: unknown; }>>)?] : [StorefrontCommonExtraParams & Pick<StorefrontQueryOptions, "cache"> & ClientVariables<StorefrontQueries, RawGqlString, AutoAddedVariableNames, "variables", RawGqlString extends never ? { [KeyType in keyof ({ [KeyType in keyof StorefrontQueries[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontQueries[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontQueries[RawGqlString]["variables"], Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>>)]: ({ [KeyType in keyof StorefrontQueries[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontQueries[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontQueries[RawGqlString]["variables"], Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>>)[KeyType]; } : { readonly [variable: string]: unknown; }, Record<"variables", RawGqlString extends never ? { [KeyType in keyof ({ [KeyType in keyof StorefrontQueries[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontQueries[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontQueries[RawGqlString]["variables"], Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>>)]: ({ [KeyType in keyof StorefrontQueries[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontQueries[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontQueries[RawGqlString]["variables"], Extract<keyof StorefrontQueries[RawGqlString]["variables"], AutoAddedVariableNames>>>)[KeyType]; } : { readonly [variable: string]: unknown; }>>]) => Promise<ClientReturn<StorefrontQueries, RawGqlString, OverrideReturnType> & StorefrontError>
- mutate
<OverrideReturnType extends unknown = never, RawGqlString extends string = string>(mutation: RawGqlString, ...options: IsOptionalVariables<StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames, Omit<StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>> extends true ? [(StorefrontCommonExtraParams & ClientVariables<StorefrontMutations, RawGqlString, AutoAddedVariableNames, "variables", RawGqlString extends never ? { [KeyType in keyof ({ [KeyType in keyof StorefrontMutations[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontMutations[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontMutations[RawGqlString]["variables"], Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>>)]: ({ [KeyType in keyof StorefrontMutations[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontMutations[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontMutations[RawGqlString]["variables"], Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>>)[KeyType]; } : { readonly [variable: string]: unknown; }, Record<"variables", RawGqlString extends never ? { [KeyType in keyof ({ [KeyType in keyof StorefrontMutations[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontMutations[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontMutations[RawGqlString]["variables"], Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>>)]: ({ [KeyType in keyof StorefrontMutations[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontMutations[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontMutations[RawGqlString]["variables"], Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>>)[KeyType]; } : { readonly [variable: string]: unknown; }>>)?] : [StorefrontCommonExtraParams & ClientVariables<StorefrontMutations, RawGqlString, AutoAddedVariableNames, "variables", RawGqlString extends never ? { [KeyType in keyof ({ [KeyType in keyof StorefrontMutations[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontMutations[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontMutations[RawGqlString]["variables"], Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>>)]: ({ [KeyType in keyof StorefrontMutations[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontMutations[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontMutations[RawGqlString]["variables"], Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>>)[KeyType]; } : { readonly [variable: string]: unknown; }, Record<"variables", RawGqlString extends never ? { [KeyType in keyof ({ [KeyType in keyof StorefrontMutations[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontMutations[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontMutations[RawGqlString]["variables"], Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>>)]: ({ [KeyType in keyof StorefrontMutations[RawGqlString]["variables"] as Filter<KeyType, Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>]: StorefrontMutations[RawGqlString]["variables"][KeyType]; } & Partial<Pick<StorefrontMutations[RawGqlString]["variables"], Extract<keyof StorefrontMutations[RawGqlString]["variables"], AutoAddedVariableNames>>>)[KeyType]; } : { readonly [variable: string]: unknown; }>>]) => Promise<ClientReturn<StorefrontMutations, RawGqlString, OverrideReturnType> & StorefrontError>
- cache
Cache
- CacheNone
() => NoStoreStrategy
- CacheLong
(overrideOptions?: AllCacheOptions) => AllCacheOptions
- CacheShort
(overrideOptions?: AllCacheOptions) => AllCacheOptions
- CacheCustom
(overrideOptions: AllCacheOptions) => AllCacheOptions
- generateCacheControlHeader
(cacheOptions: AllCacheOptions) => string
- getPublicTokenHeaders
(props?: Partial<Pick<StorefrontClientProps, "contentType">> & Pick<StorefrontClientProps, "publicStorefrontToken">) => Record<string, string>
- getPrivateTokenHeaders
(props?: Partial<Pick<StorefrontClientProps, "contentType">> & Pick<StorefrontClientProps, "privateStorefrontToken"> & { buyerIp?: string; }) => Record<string, string>
- getShopifyDomain
(props?: Partial<Pick<StorefrontClientProps, "storeDomain">>) => string
- getApiUrl
(props?: Partial<Pick<StorefrontClientProps, "storefrontApiVersion" | "storeDomain">>) => string
- i18n
TI18n
{
query: <
OverrideReturnType extends any = never,
RawGqlString extends string = string,
>(
query: RawGqlString,
...options: ClientVariablesInRestParams<
StorefrontQueries,
RawGqlString,
StorefrontCommonExtraParams & Pick<StorefrontQueryOptions, 'cache'>,
AutoAddedVariableNames
>
) => Promise<
ClientReturn<StorefrontQueries, RawGqlString, OverrideReturnType> &
StorefrontError
>;
mutate: <
OverrideReturnType extends any = never,
RawGqlString extends string = string,
>(
mutation: RawGqlString,
...options: ClientVariablesInRestParams<
StorefrontMutations,
RawGqlString,
StorefrontCommonExtraParams,
AutoAddedVariableNames
>
) => Promise<
ClientReturn<StorefrontMutations, RawGqlString, OverrideReturnType> &
StorefrontError
>;
cache?: Cache;
CacheNone: typeof CacheNone;
CacheLong: typeof CacheLong;
CacheShort: typeof CacheShort;
CacheCustom: typeof CacheCustom;
generateCacheControlHeader: typeof generateCacheControlHeader;
getPublicTokenHeaders: ReturnType<
typeof createStorefrontUtilities
>['getPublicTokenHeaders'];
getPrivateTokenHeaders: ReturnType<
typeof createStorefrontUtilities
>['getPrivateTokenHeaders'];
getShopifyDomain: ReturnType<
typeof createStorefrontUtilities
>['getShopifyDomain'];
getApiUrl: ReturnType<
typeof createStorefrontUtilities
>['getStorefrontApiUrl'];
i18n: TI18n;
}
StorefrontQueries
Maps all the queries found in the project to variables and return types.
export interface StorefrontQueries {
// Example of how a generated query type looks like:
// '#graphql query q1 {...}': {return: Q1Query; variables: Q1QueryVariables};
}
AutoAddedVariableNames
'country' | 'language'
StorefrontCommonExtraParams
- headers
HeadersInit
- storefrontApiVersion
string
- displayName
string
{
headers?: HeadersInit;
storefrontApiVersion?: string;
displayName?: string;
}
StorefrontQueryOptions
StorefrontCommonExtraParams & {
query: string;
mutation?: never;
cache?: CachingStrategy;
}
CachingStrategy
Use the `CachingStrategy` to define a custom caching mechanism for your data. Or use one of the pre-defined caching strategies: CacheNone, CacheShort, CacheLong.
- mode
The caching mode, generally `public`, `private`, or `no-store`.
string
- maxAge
The maximum amount of time in seconds that a resource will be considered fresh. See `max-age` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage).
number
- staleWhileRevalidate
Indicate that the cache should serve the stale response in the background while revalidating the cache. See `stale-while-revalidate` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate).
number
- sMaxAge
Similar to `maxAge` but specific to shared caches. See `s-maxage` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage).
number
- staleIfError
Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See `stale-if-error` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error).
number
AllCacheOptions
StorefrontError
- errors
StorefrontApiErrors
{
errors?: StorefrontApiErrors;
}
StorefrontApiErrors
JsonGraphQLError[] | undefined
StorefrontMutations
Maps all the mutations found in the project to variables and return types.
export interface StorefrontMutations {
// Example of how a generated mutation type looks like:
// '#graphql mutation m1 {...}': {return: M1Mutation; variables: M1MutationVariables};
}
NoStoreStrategy
- mode
string
{
mode: string;
}
AllCacheOptions
Override options for a cache strategy.
- mode
The caching mode, generally `public`, `private`, or `no-store`.
string
- maxAge
The maximum amount of time in seconds that a resource will be considered fresh. See `max-age` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage).
number
- staleWhileRevalidate
Indicate that the cache should serve the stale response in the background while revalidating the cache. See `stale-while-revalidate` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate).
number
- sMaxAge
Similar to `maxAge` but specific to shared caches. See `s-maxage` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage).
number
- staleIfError
Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See `stale-if-error` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error).
number
export interface AllCacheOptions {
/**
* The caching mode, generally `public`, `private`, or `no-store`.
*/
mode?: string;
/**
* The maximum amount of time in seconds that a resource will be considered fresh. See `max-age` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage).
*/
maxAge?: number;
/**
* Indicate that the cache should serve the stale response in the background while revalidating the cache. See `stale-while-revalidate` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate).
*/
staleWhileRevalidate?: number;
/**
* Similar to `maxAge` but specific to shared caches. See `s-maxage` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage).
*/
sMaxAge?: number;
/**
* Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See `stale-if-error` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error).
*/
staleIfError?: number;
}
I18nBase
- language
LanguageCode
- country
CountryCode
{
language: LanguageCode;
country: CountryCode;
}
Example code
examples
Example code
description
I am the default example
JavaScript
import {storefrontRedirect, createStorefrontClient} from '@shopify/hydrogen'; import * as remixBuild from '@remix-run/dev/server-build'; import { createRequestHandler, getStorefrontHeaders, } from '@shopify/remix-oxygen'; export default { async fetch(request, env, executionContext) { const {storefront} = createStorefrontClient({ cache: await caches.open('hydrogen'), waitUntil: (p) => executionContext.waitUntil(p), privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN, publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN, storeDomain: env.PUBLIC_STORE_DOMAIN, storefrontHeaders: getStorefrontHeaders(request), }); const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, }); const response = await handleRequest(request); if (response.status === 404) { /** * Check for redirects only when there's a 404 from * the app. If the redirect doesn't exist, then * `storefrontRedirect` will pass through the 404 * response. */ return storefrontRedirect({request, response, storefront}); } return response; }, };
TypeScript
import {storefrontRedirect, createStorefrontClient} from '@shopify/hydrogen'; import * as remixBuild from '@remix-run/dev/server-build'; import { createRequestHandler, getStorefrontHeaders, } from '@shopify/remix-oxygen'; export default { async fetch(request: Request, env: Env, executionContext: ExecutionContext) { const {storefront} = createStorefrontClient({ cache: await caches.open('hydrogen'), waitUntil: (p: Promise<unknown>) => executionContext.waitUntil(p), privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN, publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN, storeDomain: env.PUBLIC_STORE_DOMAIN, storefrontHeaders: getStorefrontHeaders(request), }); const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, }); const response = await handleRequest(request); if (response.status === 404) { /** * Check for redirects only when there's a 404 from * the app. If the redirect doesn't exist, then * `storefrontRedirect` will pass through the 404 * response. */ return storefrontRedirect({request, response, storefront}); } return response; }, };