Skip to content

Commit

Permalink
Merge pull request #193 from Shopify/fd-storefront-mutate
Browse files Browse the repository at this point in the history
Add `context.storefront.mutate`
  • Loading branch information
frandiox committed Nov 17, 2022
2 parents 347d4fc + b76b6fb commit ca61d77
Show file tree
Hide file tree
Showing 30 changed files with 376 additions and 486 deletions.
18 changes: 14 additions & 4 deletions packages/hydrogen-remix/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import type {HydrogenContext} from '@shopify/hydrogen';
import type {Params} from '@remix-run/react';
import type {AppData, DataFunctionArgs} from '@remix-run/oxygen';

export * from '@remix-run/oxygen';
export {createRequestHandler} from './server';
export * from '@shopify/hydrogen';

export type LoaderArgs = {
request: Request;
params: Params;
export type LoaderArgs = DataFunctionArgs & {
context: HydrogenContext;
};

export interface LoaderFunction {
(args: LoaderArgs): Promise<Response> | Response | Promise<AppData> | AppData;
}

export type ActionArgs = DataFunctionArgs & {
context: HydrogenContext;
};

export interface ActionFunction {
(args: ActionArgs): Promise<Response> | Response | Promise<AppData> | AppData;
}
58 changes: 43 additions & 15 deletions packages/hydrogen/storefront.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,37 @@ export type CreateStorefrontClientOptions = {
waitUntil?: ExecutionContext['waitUntil'];
};

type StorefromCommonOptions = {
variables: ExecutionArgs['variableValues'];
type StorefrontCommonOptions = {
variables?: ExecutionArgs['variableValues'];
headers?: HeadersInit;
};

export type StorefrontQueryOptions = StorefromCommonOptions & {
export type StorefrontQueryOptions = StorefrontCommonOptions & {
query: string;
mutation?: never;
cache?: CachingStrategy;
};

export type StorefrontMutationOptions = StorefromCommonOptions & {
export type StorefrontMutationOptions = StorefrontCommonOptions & {
query?: never;
mutation: string;
cache?: never;
};

const StorefrontApiError = class extends Error {} as ErrorConstructor;
export const isStorefrontApiError = (error: any) =>
error instanceof StorefrontApiError;

const isQueryRE = /(^|}\s)query[\s({]/im;
const isMutationRE = /(^|}\s)mutation[\s({]/im;

function minifyQuery(string: string) {
return string
.replace(/\s*#.*$/gm, '') // Remove GQL comments
.replace(/\s+/gm, ' ') // Minify spaces
.trim();
}

export function createStorefrontClient(
clientOptions: StorefrontClientProps,
{
Expand All @@ -82,7 +96,7 @@ export function createStorefrontClient(
defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = requestGroupId;
if (buyerIp) defaultHeaders[STOREFRONT_API_BUYER_IP_HEADER] = buyerIp;

async function getStorefrontData<T>({
async function callStorefrontApi<T>({
query,
mutation,
variables,
Expand All @@ -96,17 +110,12 @@ export function createStorefrontClient(
? Object.fromEntries(headers)
: headers;

query = (query ?? mutation)
.replace(/\s*#.*$/gm, '') // Remove GQL comments
.replace(/\s+/gm, ' ') // Minify spaces
.trim();

const url = getStorefrontApiUrl();
const requestInit = {
method: 'POST',
headers: {...defaultHeaders, ...userHeaders},
body: JSON.stringify({
query,
query: query ?? mutation,
variables,
}),
};
Expand Down Expand Up @@ -135,14 +144,30 @@ export function createStorefrontClient(

const {data, errors} = body as StorefrontApiResponse<T>;

if (errors) throwError(response, errors);
if (errors?.length) throwError(response, errors, StorefrontApiError);

return data as T;
}

return {
storefront: {
query: getStorefrontData,
query: <T>(
query: string,
payload?: StorefrontCommonOptions & {cache?: CachingStrategy},
) => {
query = minifyQuery(query);
if (isMutationRE.test(query))
throw new Error('storefront.query cannot execute mutations');

return callStorefrontApi<T>({...payload, query});
},
mutate: <T>(mutation: string, payload?: StorefrontCommonOptions) => {
mutation = minifyQuery(mutation);
if (isQueryRE.test(mutation))
throw new Error('storefront.mutate cannot execute queries');

return callStorefrontApi<T>({...payload, mutation});
},
getPublicTokenHeaders,
getPrivateTokenHeaders,
getStorefrontApiUrl,
Expand Down Expand Up @@ -173,6 +198,7 @@ export function createStorefrontClient(
function throwError<T>(
response: Response,
errors: StorefrontApiResponse<T>['errors'],
ErrorConstructor = Error,
) {
const reqId = response.headers.get('x-request-id');
const reqIdMessage = reqId ? ` - Request ID: ${reqId}` : '';
Expand All @@ -183,8 +209,10 @@ function throwError<T>(
? errors
: errors.map((error) => error.message).join('\n');

throw new Error(errorMessages + reqIdMessage);
throw new ErrorConstructor(errorMessages + reqIdMessage);
}

throw new Error(`API response error: ${response.status}` + reqIdMessage);
throw new ErrorConstructor(
`API response error: ${response.status}` + reqIdMessage,
);
}
Loading

0 comments on commit ca61d77

Please sign in to comment.