-
Notifications
You must be signed in to change notification settings - Fork 247
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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add context.storefront.mutate
#193
Changes from 8 commits
eb52537
3df7077
d26c175
3f9fd9a
dc4e941
b1ac266
1ecab1a
d00969b
51dae54
c85263a
fb93c92
6217e9a
b76b6fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,7 @@ export type CreateStorefrontClientOptions = { | |
}; | ||
|
||
type StorefromCommonOptions = { | ||
frandiox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
variables: ExecutionArgs['variableValues']; | ||
variables?: ExecutionArgs['variableValues']; | ||
headers?: HeadersInit; | ||
}; | ||
|
||
|
@@ -69,6 +69,10 @@ const shouldCacheResponse = (body: any) => { | |
} | ||
}; | ||
|
||
export class StorefrontApiError extends Error {} | ||
export const isStorefrontApiError = (error: any) => | ||
error instanceof StorefrontApiError; | ||
|
||
export function createStorefrontClient( | ||
clientOptions: StorefrontClientProps, | ||
{ | ||
|
@@ -90,7 +94,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, | ||
|
@@ -143,14 +147,27 @@ export function createStorefrontClient( | |
|
||
const {data, errors} = body as StorefrontApiResponse<T>; | ||
|
||
if (errors) throwError(response, errors); | ||
if (errors?.length) throwError(response, errors, StorefrontApiError); | ||
else if (mutation && data) { | ||
const mutationErrors = Object.values(data) | ||
.map((value: any) => value?.customerUserErrors?.[0]?.message) | ||
.filter(Boolean); | ||
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. Does this look correct? I'm not very familiar with 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. I think this looks right. @frehner what do you think? 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. I think the client should only handle connection Because cart and customer mutations return errors under different keys This way in an const {cart, errors} = await storefront.mutation(cartMutation) 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. Yeah it's unfortunate that it appears that there are different error properties on different mutations. Ugh. 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.
Nevermind, for some reason I thought the 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. I don't think you need to change it because both There's two types of errors:
What may have confused you is that I called const data = await storefront.mutation(cartMutation)
const {cart, cartUserErrors: errors} = data; Does that make sense? 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. Ah, I modified my comment earlier without refreshing the page so I didn't see your last comment @juanpprieto , but yeah it makes sense, thanks! |
||
|
||
if (mutationErrors.length) | ||
throwError(response, mutationErrors, StorefrontApiError); | ||
} | ||
|
||
return data as T; | ||
} | ||
|
||
return { | ||
storefront: { | ||
query: getStorefrontData, | ||
query: <T>( | ||
query: string, | ||
payload?: StorefromCommonOptions & {cache?: CachingStrategy}, | ||
) => callStorefrontApi<T>({...payload, query}), | ||
mutate: <T>(mutation: string, payload?: StorefromCommonOptions) => | ||
callStorefrontApi<T>({...payload, mutation}), | ||
getPublicTokenHeaders, | ||
getPrivateTokenHeaders, | ||
getStorefrontApiUrl, | ||
|
@@ -181,6 +198,7 @@ export function createStorefrontClient( | |
function throwError<T>( | ||
response: Response, | ||
errors: StorefrontApiResponse<T>['errors'], | ||
ErrorConstructor: any = Error, | ||
frandiox marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) { | ||
const reqId = response.headers.get('x-request-id'); | ||
const reqIdMessage = reqId ? ` - Request ID: ${reqId}` : ''; | ||
|
@@ -191,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, | ||
); | ||
} |
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.