-
Notifications
You must be signed in to change notification settings - Fork 214
Make API clients injectable in commerce-sdk-react (CommerceApiProvider) #2519
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
Changes from 25 commits
8190025
cbd8e1e
7fa34b2
437e164
5f99885
6138000
faf0069
03fbbb6
1b80c10
b0b0e20
749baef
b6fb54a
fff68c0
0ab0673
8c7507c
5d74541
7e7aada
76c6cbf
3698a4a
576792a
dbc0599
78f0a13
95af8a5
149df85
b6b5f11
9d95e11
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 |
|---|---|---|
|
|
@@ -5,6 +5,15 @@ | |
| * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
| */ | ||
| import React, {ReactElement, useEffect, useMemo} from 'react' | ||
| import Auth from './auth' | ||
| import {ApiClientConfigParams, ApiClients, SDKClientTransformer} from './hooks/types' | ||
| import {Logger} from './types' | ||
| import { | ||
| DWSID_COOKIE_NAME, | ||
| MOBIFY_PATH, | ||
| SERVER_AFFINITY_HEADER_KEY, | ||
| SLAS_PRIVATE_PROXY_PATH | ||
| } from './constant' | ||
| import { | ||
| ShopperBaskets, | ||
| ShopperContexts, | ||
|
|
@@ -20,15 +29,8 @@ import { | |
| ShopperBasketsTypes, | ||
| ShopperStores | ||
| } from 'commerce-sdk-isomorphic' | ||
| import Auth from './auth' | ||
| import {ApiClientConfigParams, ApiClients} from './hooks/types' | ||
| import {Logger} from './types' | ||
| import { | ||
| DWSID_COOKIE_NAME, | ||
| MOBIFY_PATH, | ||
| SERVER_AFFINITY_HEADER_KEY, | ||
| SLAS_PRIVATE_PROXY_PATH | ||
| } from './constant' | ||
| import {transformSDKClient} from './utils' | ||
|
|
||
| export interface CommerceApiProviderProps extends ApiClientConfigParams { | ||
| children: React.ReactNode | ||
| proxy: string | ||
|
|
@@ -46,6 +48,7 @@ export interface CommerceApiProviderProps extends ApiClientConfigParams { | |
| passwordlessLoginCallbackURI?: string | ||
| refreshTokenRegisteredCookieTTL?: number | ||
| refreshTokenGuestCookieTTL?: number | ||
| apiClients?: ApiClients | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -56,7 +59,9 @@ export const CommerceApiContext = React.createContext({} as ApiClients) | |
| /** | ||
| * @internal | ||
| */ | ||
| export const ConfigContext = React.createContext({} as Omit<CommerceApiProviderProps, 'children'>) | ||
| export const ConfigContext = React.createContext( | ||
| {} as Omit<CommerceApiProviderProps, 'children' | 'apiClients'> | ||
| ) | ||
|
|
||
| /** | ||
| * @internal | ||
|
|
@@ -126,7 +131,8 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => { | |
| defaultDnt, | ||
| passwordlessLoginCallbackURI, | ||
| refreshTokenRegisteredCookieTTL, | ||
| refreshTokenGuestCookieTTL | ||
| refreshTokenGuestCookieTTL, | ||
| apiClients | ||
| } = props | ||
|
|
||
| // Set the logger based on provided configuration, or default to the console object if no logger is provided | ||
|
|
@@ -167,7 +173,8 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => { | |
| defaultDnt, | ||
| passwordlessLoginCallbackURI, | ||
| refreshTokenRegisteredCookieTTL, | ||
| refreshTokenGuestCookieTTL | ||
| refreshTokenGuestCookieTTL, | ||
| apiClients | ||
| ]) | ||
|
|
||
| const dwsid = auth.get(DWSID_COOKIE_NAME) | ||
|
|
@@ -176,28 +183,62 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => { | |
| serverAffinityHeader[SERVER_AFFINITY_HEADER_KEY] = dwsid | ||
| } | ||
|
|
||
| const config = { | ||
| proxy, | ||
| headers: { | ||
| ...headers, | ||
| ...serverAffinityHeader | ||
| }, | ||
| parameters: { | ||
| clientId, | ||
| organizationId, | ||
| shortCode, | ||
| siteId, | ||
| locale, | ||
| currency | ||
| }, | ||
| throwOnBadResponse: true, | ||
| fetchOptions | ||
| const _defaultTransformer: SDKClientTransformer<Record<string, any>> = (_, _$, options) => { | ||
|
Contributor
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 see the first 2 arguments to this function are not being used. So do we really need them? Besides, it doesn't look like there's a way for the end user to pass in their own transformer.
Contributor
Author
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 v2 integration is in a separate PR.
We're not using those arguments now: those 2 are props and methodName but we might need them for some future change. I could convert the props to transformer to be an object with optional properties to make it clear. Also, we're not accepting a transformer from the end user for now is because they already have props in CommerceApiProvider where they can pass in all the different headers and options and our default transformer and SDK initialization already accepts all that when creating an instance. However, the transformSDKClient function is open to accept any transformer function so in the future if we come across a use-case to allow the customer to pass in a transformer we can easily do that by simply creating another options prop for commerceApi. I haven't added that today because I don't see a direct use-case for that right now. |
||
| return { | ||
| ...options, | ||
| headers: { | ||
| ...options.headers, | ||
| ...serverAffinityHeader | ||
| }, | ||
| throwOnBadResponse: true, | ||
| fetchOptions: { | ||
| ...options.fetchOptions, | ||
| ...fetchOptions | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const baseUrl = config.proxy.split(MOBIFY_PATH)[0] | ||
| const privateClientEndpoint = `${baseUrl}${SLAS_PRIVATE_PROXY_PATH}` | ||
| const updatedClients: ApiClients = useMemo(() => { | ||
| if (apiClients) { | ||
shethj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const clients: Record<string, any> = {} | ||
|
|
||
| // transformSDKClient is simply a utility function that wraps the SDK Client instance | ||
| // in a Proxy that allows us to transform the method arguments and modify headers, parameters, and other options. | ||
| // We don't really need to pass in the children prop to the transformer function, so we'll just pass in the rest of the props. | ||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const {children, ...restProps} = props | ||
|
|
||
| Object.entries(apiClients ?? {}).forEach(([key, apiClient]) => { | ||
| clients[key] = transformSDKClient(apiClient, { | ||
| props: restProps, | ||
| transformer: _defaultTransformer | ||
| }) | ||
| }) | ||
|
|
||
| return clients as ApiClients | ||
| } | ||
|
|
||
| const config = { | ||
| proxy, | ||
| headers: { | ||
| ...headers, | ||
| ...serverAffinityHeader | ||
| }, | ||
| parameters: { | ||
| clientId, | ||
| organizationId, | ||
| shortCode, | ||
| siteId, | ||
| locale, | ||
| currency | ||
| }, | ||
| throwOnBadResponse: true, | ||
| fetchOptions | ||
| } | ||
|
|
||
| const baseUrl = config.proxy.split(MOBIFY_PATH)[0] | ||
| const privateClientEndpoint = `${baseUrl}${SLAS_PRIVATE_PROXY_PATH}` | ||
|
|
||
| const apiClients = useMemo(() => { | ||
| return { | ||
| shopperBaskets: new ShopperBaskets(config), | ||
| shopperContexts: new ShopperContexts(config), | ||
|
|
@@ -224,7 +265,8 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => { | |
| fetchOptions, | ||
| locale, | ||
| currency, | ||
| headers?.['correlation-id'] | ||
| headers?.['correlation-id'], | ||
| apiClients | ||
| ]) | ||
|
|
||
| // Initialize the session | ||
|
|
@@ -251,7 +293,7 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => { | |
| refreshTokenGuestCookieTTL | ||
| }} | ||
| > | ||
| <CommerceApiContext.Provider value={apiClients}> | ||
| <CommerceApiContext.Provider value={updatedClients}> | ||
| <AuthContext.Provider value={auth}>{children}</AuthContext.Provider> | ||
| </CommerceApiContext.Provider> | ||
| </ConfigContext.Provider> | ||
|
|
||
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.
From what I see in the default transformer, it looks like the return object is like
optionsbut with some overrides/additions. If that's the case, can we make the type clearer?