-
Notifications
You must be signed in to change notification settings - Fork 273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add context.storefront.mutate
#193
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
eb52537
Change storefront.query API
frandiox 3df7077
Update storefront.query calls
frandiox d26c175
Override LoaderFunction, ActionFunction and ActionArgs types
frandiox 3f9fd9a
Update queries to use storefront.query
frandiox dc4e941
Check customerUserErrors in storefront.mutate
frandiox b1ac266
Use StorefrontApiError constructor for payload errors
frandiox 1ecab1a
Throw conditionally
frandiox d00969b
Update mutations to use storefront.mutate
frandiox 51dae54
Use ErrorConstructor type
frandiox c85263a
Move data error handling to user app
frandiox fb93c92
Fix type name
frandiox 6217e9a
Assert query type
frandiox b76b6fb
Merge branch 'main' into fd-storefront-mutate
frandiox File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, | ||
{ | ||
|
@@ -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, | ||
|
@@ -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, | ||
}), | ||
}; | ||
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any value in providing an option for users to opt out of minifying for debugging, etc... |
||
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, | ||
|
@@ -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}` : ''; | ||
|
@@ -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, | ||
); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't these essentially the same as what Remix provides? Why not use their types instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think is because we are modifying DataFunctionArgs['context']?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we are modifying
context
to beHydrogenContext
, that's the only reason.