fix: improve Shopify error handling and prevent server crash on invalid cart

This commit is contained in:
samandeepbishnoi 2025-07-07 21:13:10 +05:30
parent fa1306916c
commit b9af6f6b9a
4 changed files with 2193 additions and 33 deletions

View File

@ -3,3 +3,4 @@ SITE_NAME="Next.js Commerce"
SHOPIFY_REVALIDATION_SECRET=""
SHOPIFY_STOREFRONT_ACCESS_TOKEN=""
SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com"
SHOPIFY_STOREFRONT_API_VERSION= "2025-04"

View File

@ -28,4 +28,4 @@ export const TAGS = {
export const HIDDEN_PRODUCT_TAG = 'nextjs-frontend-hidden';
export const DEFAULT_OPTION = 'Default Title';
export const SHOPIFY_GRAPHQL_API_ENDPOINT = '/api/2023-01/graphql.json';
export const SHOPIFY_GRAPHQL_API_ENDPOINT = `/api/${process.env.SHOPIFY_STOREFRONT_API_VERSION}/graphql.json`;

View File

@ -61,8 +61,11 @@ import {
const domain = process.env.SHOPIFY_STORE_DOMAIN
? ensureStartsWith(process.env.SHOPIFY_STORE_DOMAIN, 'https://')
: '';
const endpoint = `${domain}${SHOPIFY_GRAPHQL_API_ENDPOINT}`;
const key = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!;
export const endpoint = `${domain}${SHOPIFY_GRAPHQL_API_ENDPOINT}`;
// Your Shopify Storefront access token
export const key = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!;
type ExtractVariables<T> = T extends { variables: object }
? T['variables']
@ -76,7 +79,7 @@ export async function shopifyFetch<T>({
headers?: HeadersInit;
query: string;
variables?: ExtractVariables<T>;
}): Promise<{ status: number; body: T } | never> {
}): Promise<{ status: number; body: T }> {
try {
const result = await fetch(endpoint, {
method: 'POST',
@ -93,28 +96,35 @@ export async function shopifyFetch<T>({
const body = await result.json();
// Handle API-level errors
if (body.errors) {
throw body.errors[0];
console.error('[shopifyFetch] Shopify API error:', {
query,
status: result.status,
error: body.errors[0]
});
// Throw a standard Error object (not a plain object)
throw new Error(
`Shopify API Error (${result.status}): ${body.errors[0].message}`
);
}
return {
status: result.status,
body
};
} catch (e) {
if (isShopifyError(e)) {
throw {
cause: e.cause?.toString() || 'unknown',
status: e.status || 500,
message: e.message,
query
};
}
} catch (err: any) {
// Log full context for unknown or fetch-level errors
console.error('[shopifyFetch] Unexpected fetch error:', {
query,
error: err
});
throw {
error: e,
query
};
// Re-throw a standard Error to be caught elsewhere
throw new Error(
`Unexpected error in shopifyFetch: ${err?.message ?? err}`
);
}
}
@ -264,9 +274,11 @@ export async function updateCart(
}
export async function getCart(): Promise<Cart | undefined> {
try {
const cartId = (await cookies()).get('cartId')?.value;
if (!cartId) {
console.warn('[getCart] No cartId in cookies');
return undefined;
}
@ -275,12 +287,16 @@ export async function getCart(): Promise<Cart | undefined> {
variables: { cartId }
});
// Old carts becomes `null` when you checkout.
if (!res.body.data.cart) {
if (!res.body?.data?.cart) {
console.warn('[getCart] Cart is null for cartId:', cartId);
return undefined;
}
return reshapeCart(res.body.data.cart);
} catch (err) {
console.error('[getCart] Failed:', err);
return undefined;
}
}
export async function getCollection(

2143
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff