Creates an API that can be used to interact with the cart.
import {
createStorefrontClient,
createCartHandler,
cartGetIdDefault,
cartSetIdDefault,
} 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({
/* client parameters */
});
// Create a cart api instance.
const cart = createCartHandler({
storefront,
getCartId: cartGetIdDefault(request.headers),
setCartId: cartSetIdDefault(),
});
const handleRequest = createRequestHandler({
build: remixBuild,
mode: process.env.NODE_ENV,
getLoadContext: () => ({
storefront,
cart, // Pass the cart api instance to the loader context.
}),
});
return await handleRequest(request);
},
};
import {
createStorefrontClient,
createCartHandler,
cartGetIdDefault,
cartSetIdDefault,
} 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: Record<string, string>,
executionContext: ExecutionContext,
): Promise<Response> {
const {storefront} = createStorefrontClient({
/* client parameters */
});
// Create a cart api instance.
const cart = createCartHandler({
storefront,
getCartId: cartGetIdDefault(request.headers),
setCartId: cartSetIdDefault(),
});
const handleRequest = createRequestHandler({
build: remixBuild,
mode: process.env.NODE_ENV,
getLoadContext: () => ({
storefront,
cart, // Pass the cart api instance to the loader context.
}),
});
return await handleRequest(request);
},
};
A function that returns the cart id in the form of `gid://shopify/Cart/c1-123`.
A function that sets the cart ID.
The storefront client instance created by [`createStorefrontClient`](docs/api/hydrogen/latest/utilities/createstorefrontclient).
The cart mutation fragment used in most mutation requests, except for `setMetafields` and `deleteMetafield`. See the [example usage](/docs/api/hydrogen/2023-10/utilities/createcarthandler#example-cart-fragments) in the documentation.
The cart query fragment used by `cart.get()`. See the [example usage](/docs/api/hydrogen/2023-10/utilities/createcarthandler#example-cart-fragments) in the documentation.
Define custom methods or override existing methods for your cart API instance. See the [example usage](/docs/api/hydrogen/2023-10/utilities/createcarthandler#example-custom-methods) in the documentation.
Headers
Interface to interact with the Storefront API.
The function to run a query on Storefront API.
The function to run a mutation on Storefront API.
The cache instance passed in from the `createStorefrontClient` argument.
Re-export of [`CacheNone`](/docs/api/hydrogen/2023-10/utilities/cachenone).
Re-export of [`CacheLong`](/docs/api/hydrogen/2023-10/utilities/cachelong).
Re-export of [`CacheShort`](/docs/api/hydrogen/2023-10/utilities/cacheshort).
Re-export of [`CacheCustom`](/docs/api/hydrogen/2023-10/utilities/cachecustom).
Re-export of [`generateCacheControlHeader`](/docs/api/hydrogen/2023-10/utilities/generatecachecontrolheader).
Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. See [`getPublicTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/2023-10/utilities/createstorefrontclient#:~:text=%27graphql%27.-,getPublicTokenHeaders,-(props%3F%3A) for more details.
Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint for API calls made from a server. See [`getPrivateTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/2023-10/utilities/createstorefrontclient#:~:text=storefrontApiVersion-,getPrivateTokenHeaders,-(props%3F%3A) for more details.
Creates the fully-qualified URL to your myshopify.com domain. See [`getShopifyDomain` in Hydrogen React](/docs/api/hydrogen-react/2023-10/utilities/createstorefrontclient#:~:text=StorefrontClientReturn-,getShopifyDomain,-(props%3F%3A) for more details.
Creates the fully-qualified URL to your store's GraphQL endpoint. See [`getStorefrontApiUrl` in Hydrogen React](/docs/api/hydrogen-react/2023-10/utilities/createstorefrontclient#:~:text=storeDomain-,getStorefrontApiUrl,-(props%3F%3A) for more details.
Determines if the error is resulted from a Storefront API call.
The `i18n` object passed in from the `createStorefrontClient` argument.
Omit< OperationTypeValue['variables'], AutoAddedVariableNames > extends EmptyVariables ? true // No need to pass variables : GenericVariables extends OperationTypeValue['variables'] ? true // We don't know what variables are needed : false
'country' | 'language'
{[key: string]: never}
ExecutionArgs['variableValues']
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}; }
(RawGqlString extends keyof StorefrontQueries ? StorefrontCommonOptions<StorefrontQueries[RawGqlString]['variables']> : StorefrontCommonOptions<GenericVariables>) & {cache?: CachingStrategy}
{ headers?: HeadersInit; storefrontApiVersion?: string; } & (IsOptionalVariables<{variables: Variables}> extends true ? {variables?: Variables} : {variables: Variables})
Use the `CachingStrategy` to define a custom caching mechanism for your data. Or use one of the pre-defined caching strategies: CacheNone, CacheShort, CacheLong.
The caching mode, generally `public`, `private`, or `no-store`.
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).
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).
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).
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).
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}; }
RawGqlString extends keyof StorefrontMutations ? StorefrontCommonOptions<StorefrontMutations[RawGqlString]['variables']> : StorefrontCommonOptions<GenericVariables>
Override options for a cache strategy.
The caching mode, generally `public`, `private`, or `no-store`.
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).
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).
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).
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).
The handler returns the following default methods. Any [custom](/docs/api/hydrogen/2023-10/utilities/createcarthandler#example-custom-methods) or overwritten methods will also be available in the returned cart instance.
Adds items to the cart. If the cart doesn't exist, a new one will be created.
Creates a new cart.
Removes a custom field (metafield) from the cart.
Retrieves the cart information.
Retrieves the unique identifier of the cart. By default, it gets the ID from the request cookie.
Removes items from the cart.
Sets the unique identifier of the cart. By default, it sets the ID in the header cookie.
Adds extra information (metafields) to the cart. If the cart doesn't exist, a new one will be created.
Updates additional information (attributes) in the cart.
Updates the buyer's information in the cart. If the cart doesn't exist, a new one will be created.
Updates discount codes in the cart.
Updates items in the cart.
Updates the note in the cart. If the cart doesn't exist, a new one will be created.
Updates the selected delivery options in the cart. Only available for carts associated with a customer access token.
lines: CartLineInput[]
optionalParams: CartOptionalInput
export type CartLinesAddFunction = ( lines: CartLineInput[], optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
CartLineInput
The cart id.
The country code.
The language code.
Cart
CartUserError
MetafieldsSetUserError
MetafieldDeleteUserError
input: CartInput
optionalParams: CartOptionalInput
export type CartCreateFunction = ( input: CartInput, optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
CartInput
key: string
optionalParams: CartOptionalInput
export type CartMetafieldDeleteFunction = ( key: Scalars['String']['input'], optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
cartInput: CartGetProps
export type CartGetFunction = ( cartInput?: CartGetProps, ) => Promise<Cart | null>;
The cart ID.
The country code.
The language code.
The number of cart lines to be returned.
lineIds: string[]
optionalParams: CartOptionalInput
export type CartLinesRemoveFunction = ( lineIds: string[], optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
Headers
metafields: MetafieldWithoutOwnerId[]
optionalParams: CartOptionalInput
export type CartMetafieldsSetFunction = ( metafields: MetafieldWithoutOwnerId[], optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
MetafieldWithoutOwnerId
attributes: AttributeInput[]
optionalParams: CartOptionalInput
export type CartAttributesUpdateFunction = ( attributes: AttributeInput[], optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
AttributeInput
buyerIdentity: CartBuyerIdentityInput
optionalParams: CartOptionalInput
export type CartBuyerIdentityUpdateFunction = ( buyerIdentity: CartBuyerIdentityInput, optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
CartBuyerIdentityInput
discountCodes: string[]
optionalParams: CartOptionalInput
export type CartDiscountCodesUpdateFunction = ( discountCodes: string[], optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
lines: CartLineUpdateInput[]
optionalParams: CartOptionalInput
export type CartLinesUpdateFunction = ( lines: CartLineUpdateInput[], optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
CartLineUpdateInput
note: string
optionalParams: CartOptionalInput
export type CartNoteUpdateFunction = ( note: string, optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
selectedDeliveryOptions: CartSelectedDeliveryOptionInput[]
optionalParams: CartOptionalInput
export type CartSelectedDeliveryOptionsUpdateFunction = ( selectedDeliveryOptions: CartSelectedDeliveryOptionInput[], optionalParams?: CartOptionalInput, ) => Promise<CartQueryData>;
CartSelectedDeliveryOptionInput
Creates an API that can be used to interact with the cart.
import {
createCartHandler,
cartGetIdDefault,
cartSetIdDefault,
} from '@shopify/hydrogen';
// Override cart fragments
const cart = createCartHandler({
storefront,
getCartId: cartGetIdDefault(request.headers),
setCartId: cartSetIdDefault(),
cartQueryFragment: CART_QUERY_FRAGMENT,
cartMutateFragment: CART_MUTATE_FRAGMENT,
});
// cartQueryFragment requirements:
// - Must be named `CartApiQuery`
// - Only have access to the following query variables:
// - $cartId: ID!
// - $country: CountryCode
// - $language: LanguageCode
// - $numCartLines: Int
const CART_QUERY_FRAGMENT = `#graphql
fragment CartApiQuery on Cart {
id
totalQuantity
checkoutUrl
note
}
`;
// cartMutateFragment requirements:
// - Must be named `CartApiMutation`
// - Only have access to the following query variables:
// - $cartId: ID!
// - $country: CountryCode
// - $language: LanguageCode
const CART_MUTATE_FRAGMENT = `#graphql
fragment CartApiMutation on Cart {
id
totalQuantity
checkoutUrl
lines(first: 100) {
edges {
node {
id
quantity
}
}
}
}
`;
import {
createCartHandler,
cartGetIdDefault,
cartSetIdDefault,
cartLinesAddDefault,
cartLinesRemoveDefault,
} from '@shopify/hydrogen';
const cartQueryOptions = {
storefront,
getCartId: cartGetIdDefault(request.headers),
};
const getCartId = cartGetIdDefault(request.headers);
const cart = createCartHandler({
storefront,
getCartId,
setCartId: cartSetIdDefault(),
customMethods: {
editInLine: async (addLines, removeLineIds, optionalParams) => {
// Using Hydrogen default cart query methods
await cartLinesAddDefault(cartQueryOptions)(addLines, optionalParams);
return await cartLinesRemoveDefault(cartQueryOptions)(
removeLineIds,
optionalParams,
);
},
addLines: async (lines, optionalParams) => {
// With your own Storefront API graphql query
return await storefront.mutate(CART_LINES_ADD_MUTATION, {
variables: {
id: optionalParams.cartId || getCartId(),
lines,
},
});
},
},
});
// Use custom method editInLine that delete and add items in one method
cart.editInLine(
['123'],
[
{
merchandiseId: 'gid://shopify/ProductVariant/456789123',
quantity: 1,
},
],
);
// Use overridden cart.addLines
const result = await cart.addLines(
[
{
merchandiseId: 'gid://shopify/ProductVariant/123456789',
quantity: 1,
},
],
{
cartId: 'c-123',
},
);
// Output of result:
// {
// cartLinesAdd: {
// cart: {
// id: 'c-123',
// totalQuantity: 1
// },
// errors: []
// }
// }
const CART_LINES_ADD_MUTATION = `#graphql
mutation CartLinesAdd(
$cartId: ID!
$lines: [CartLineInput!]!
$country: CountryCode = ZZ
$language: LanguageCode
) @inContext(country: $country, language: $language) {
cartLinesAdd(cartId: $cartId, lines: $lines) {
cart {
id
totalQuantity
}
errors: userErrors {
message
field
code
}
}
}
`;
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.addLines(
[
{
merchandiseId: 'gid://shopify/ProductVariant/123456789',
quantity: 1,
},
],
// Optional parameters
{
cartId: '123', // override the cart id
country: 'US', // override the country code to 'US'
language: 'EN', // override the language code to 'EN'
},
);
}
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 1
// },
// errors: []
// }
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.create(
{
lines: [
{
merchandiseId: 'gid://shopify/ProductVariant/123456789',
quantity: 1,
},
],
discountCodes: ['FREE_SHIPPING'],
},
// Optional parameters
{
cartId: '123', // override the cart id
country: 'US', // override the country code to 'US'
language: 'EN', // override the language code to 'EN'
},
);
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 1,
// discountCodes: [{ code: 'FREE_SHIPPING'}]
// },
// errors: []
// }
}
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.setMetafields(
[
{
key: 'custom.gift',
type: 'boolean',
value: 'true',
},
],
// Optional parameters
{
cartId: '123', // override the cart id
},
);
const result2 = await cart.deleteMetafield(
'custom.gift',
// Optional parameters
{
cartId: '123', // override the cart id
},
);
}
// server.js
// To query for metafields, use the `cartQueryFragment` option when creating the cart handler.
import {
createCartHandler,
cartGetIdDefault,
cartSetIdDefault,
} from '@shopify/hydrogen';
const cart = createCartHandler({
storefront,
getCartId: cartGetIdDefault(request.headers),
setCartId: cartSetIdDefault(),
cartQueryFragment: CART_QUERY_FRAGMENT,
});
const CART_QUERY_FRAGMENT = `#graphql
fragment CartApiQuery on Cart {
id
metafields(
identifiers: [{
namespace: "custom",
key: "gift"
])
{
namespace
key
type
value
}
}
`;
export async function loader({context}) {
const {cart} = context;
// Usage
const result = await cart.get();
// Optional parameters
const result2 = await cart.get({
cartId: '123', // override the cart id
numCartLines: 50, //override to return 50 cart lines
country: 'US', // override the country code to 'US'
language: 'EN', // override the language code to 'EN'
});
}
export async function loader({context}) {
// Usage
context.cart.getCartId(); // 'gid://shopify/Cart/123'
}
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.removeLines(
['123'],
// Optional parameters
{
cartId: '123', // override the cart id
country: 'US', // override the country code to 'US'
language: 'EN', // override the language code to 'EN'
},
);
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 0
// },
// errors: []
// }
}
export async function action({context}) {
const {cart} = context;
const result = await cart.addLines([
{
merchandiseId: 'gid://shopify/ProductVariant/123456789',
quantity: 1,
},
]);
// Usage
const headers = cart.setCartId(result.cart.id);
}
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.setMetafields(
[
{
key: 'custom.gift',
type: 'boolean',
value: 'true',
},
],
// Optional parameters
{
cartId: '123', // override the cart id
},
);
const result2 = await cart.deleteMetafield(
'custom.gift',
// Optional parameters
{
cartId: '123', // override the cart id
},
);
}
// server.js
// To query for metafields, use the `cartQueryFragment` option when creating the cart handler.
import {
createCartHandler,
cartGetIdDefault,
cartSetIdDefault,
} from '@shopify/hydrogen';
const cart = createCartHandler({
storefront,
getCartId: cartGetIdDefault(request.headers),
setCartId: cartSetIdDefault(),
cartQueryFragment: CART_QUERY_FRAGMENT,
});
const CART_QUERY_FRAGMENT = `#graphql
fragment CartApiQuery on Cart {
id
metafields(
identifiers: [{
namespace: "custom",
key: "gift"
])
{
namespace
key
type
value
}
}
`;
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.updateAttributes(
[
{
key: 'Somekey',
value: '1',
},
],
// Optional parameters
{
cartId: '123', // override the cart id
},
);
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 1
// },
// errors: []
// }
}
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.updateBuyerIdentity(
{
customerAccessToken: '123',
},
// Optional parameters
{
cartId: '123', // override the cart id
country: 'US', // override the country code to 'US'
language: 'EN', // override the language code to 'EN'
},
);
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 1
// },
// errors: []
// }
}
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.updateDiscountCodes(
['FREE_SHIPPING'],
// Optional parameters
{
cartId: '123', // override the cart id
country: 'US', // override the country code to 'US'
language: 'EN', // override the language code to 'EN'
},
);
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 1
// },
// errors: []
// }
}
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.updateLines(
[
{
merchandiseId: 'gid://shopify/ProductVariant/123456789',
quantity: 2,
},
],
// Optional parameters
{
cartId: '123', // override the cart id
country: 'US', // override the country code to 'US'
language: 'EN', // override the language code to 'EN'
},
);
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 2
// },
// errors: []
// }
}
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.updateNote(
'Some notes',
// Optional parameters
{
cartId: '123', // override the cart id
},
);
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 0
// },
// errors: []
// }
}
export async function action({context}) {
const {cart} = context;
// Usage
const result = await cart.updateSelectedDeliveryOptions(
[
{
deliveryGroupId: '123',
deliveryOptionHandle: 'Canada Post',
},
],
// Optional parameters
{
cartId: '123', // override the cart id
country: 'US', // override the country code to 'US'
language: 'EN', // override the language code to 'EN'
},
);
// Output of result:
// {
// cart: {
// id: 'c1-123',
// totalQuantity: 2
// },
// errors: []
// }
}