avoid circular dependency in bigcommerce

This commit is contained in:
Tobias Koppers 2021-06-14 23:06:54 +02:00
parent f01ebc549f
commit e0da7f4261
3 changed files with 79 additions and 81 deletions

View File

@ -4,8 +4,8 @@ import {
CommerceAPIConfig, CommerceAPIConfig,
getCommerceApi as commerceApi, getCommerceApi as commerceApi,
} from '@commerce/api' } from '@commerce/api'
import fetchGraphqlApi from './utils/fetch-graphql-api' import createFetchGraphqlApi from './utils/fetch-graphql-api'
import fetchStoreApi from './utils/fetch-store-api' import createFetchStoreApi from './utils/fetch-store-api'
import type { CartAPI } from './endpoints/cart' import type { CartAPI } from './endpoints/cart'
import type { CustomerAPI } from './endpoints/customer' import type { CustomerAPI } from './endpoints/customer'
@ -68,14 +68,14 @@ const config: BigcommerceConfig = {
customerCookie: 'SHOP_TOKEN', customerCookie: 'SHOP_TOKEN',
cartCookie: process.env.BIGCOMMERCE_CART_COOKIE ?? 'bc_cartId', cartCookie: process.env.BIGCOMMERCE_CART_COOKIE ?? 'bc_cartId',
cartCookieMaxAge: ONE_DAY * 30, cartCookieMaxAge: ONE_DAY * 30,
fetch: fetchGraphqlApi, fetch: createFetchGraphqlApi(() => getCommerceApi().getConfig()),
applyLocale: true, applyLocale: true,
// REST API only // REST API only
storeApiUrl: STORE_API_URL, storeApiUrl: STORE_API_URL,
storeApiToken: STORE_API_TOKEN, storeApiToken: STORE_API_TOKEN,
storeApiClientId: STORE_API_CLIENT_ID, storeApiClientId: STORE_API_CLIENT_ID,
storeChannelId: STORE_CHANNEL_ID, storeChannelId: STORE_CHANNEL_ID,
storeApiFetch: fetchStoreApi, storeApiFetch: createFetchStoreApi(() => getCommerceApi().getConfig()),
} }
const operations = { const operations = {

View File

@ -1,38 +1,36 @@
import { FetcherError } from '@commerce/utils/errors' import { FetcherError } from '@commerce/utils/errors'
import type { GraphQLFetcher } from '@commerce/api' import type { GraphQLFetcher } from '@commerce/api'
import { provider } from '..' import type { BigcommerceConfig } from '../index'
import fetch from './fetch' import fetch from './fetch'
const fetchGraphqlApi: GraphQLFetcher = async ( const fetchGraphqlApi: (getConfig: () => BigcommerceConfig) => GraphQLFetcher =
query: string, (getConfig) =>
{ variables, preview } = {}, async (query: string, { variables, preview } = {}, fetchOptions) => {
fetchOptions // log.warn(query)
) => { const config = getConfig()
// log.warn(query) const res = await fetch(config.commerceUrl + (preview ? '/preview' : ''), {
const { config } = provider ...fetchOptions,
const res = await fetch(config.commerceUrl + (preview ? '/preview' : ''), { method: 'POST',
...fetchOptions, headers: {
method: 'POST', Authorization: `Bearer ${config.apiToken}`,
headers: { ...fetchOptions?.headers,
Authorization: `Bearer ${config.apiToken}`, 'Content-Type': 'application/json',
...fetchOptions?.headers, },
'Content-Type': 'application/json', body: JSON.stringify({
}, query,
body: JSON.stringify({ variables,
query, }),
variables,
}),
})
const json = await res.json()
if (json.errors) {
throw new FetcherError({
errors: json.errors ?? [{ message: 'Failed to fetch Bigcommerce API' }],
status: res.status,
}) })
const json = await res.json()
if (json.errors) {
throw new FetcherError({
errors: json.errors ?? [{ message: 'Failed to fetch Bigcommerce API' }],
status: res.status,
})
}
return { data: json.data, res }
} }
return { data: json.data, res }
}
export default fetchGraphqlApi export default fetchGraphqlApi

View File

@ -1,56 +1,56 @@
import type { RequestInit, Response } from '@vercel/fetch' import type { RequestInit, Response } from '@vercel/fetch'
import { provider } from '..' import type { BigcommerceConfig } from '../index'
import { BigcommerceApiError, BigcommerceNetworkError } from './errors' import { BigcommerceApiError, BigcommerceNetworkError } from './errors'
import fetch from './fetch' import fetch from './fetch'
export default async function fetchStoreApi<T>( const fetchStoreApi =
endpoint: string, <T>(getConfig: () => BigcommerceConfig) =>
options?: RequestInit async (endpoint: string, options?: RequestInit): Promise<T> => {
): Promise<T> { const config = getConfig()
const { config } = provider let res: Response
let res: Response
try { try {
res = await fetch(config.storeApiUrl + endpoint, { res = await fetch(config.storeApiUrl + endpoint, {
...options, ...options,
headers: { headers: {
...options?.headers, ...options?.headers,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Auth-Token': config.storeApiToken, 'X-Auth-Token': config.storeApiToken,
'X-Auth-Client': config.storeApiClientId, 'X-Auth-Client': config.storeApiClientId,
}, },
}) })
} catch (error) { } catch (error) {
throw new BigcommerceNetworkError( throw new BigcommerceNetworkError(
`Fetch to Bigcommerce failed: ${error.message}` `Fetch to Bigcommerce failed: ${error.message}`
) )
}
const contentType = res.headers.get('Content-Type')
const isJSON = contentType?.includes('application/json')
if (!res.ok) {
const data = isJSON ? await res.json() : await getTextOrNull(res)
const headers = getRawHeaders(res)
const msg = `Big Commerce API error (${
res.status
}) \nHeaders: ${JSON.stringify(headers, null, 2)}\n${
typeof data === 'string' ? data : JSON.stringify(data, null, 2)
}`
throw new BigcommerceApiError(msg, res, data)
}
if (res.status !== 204 && !isJSON) {
throw new BigcommerceApiError(
`Fetch to Bigcommerce API failed, expected JSON content but found: ${contentType}`,
res
)
}
// If something was removed, the response will be empty
return res.status === 204 ? null : await res.json()
} }
export default fetchStoreApi
const contentType = res.headers.get('Content-Type')
const isJSON = contentType?.includes('application/json')
if (!res.ok) {
const data = isJSON ? await res.json() : await getTextOrNull(res)
const headers = getRawHeaders(res)
const msg = `Big Commerce API error (${
res.status
}) \nHeaders: ${JSON.stringify(headers, null, 2)}\n${
typeof data === 'string' ? data : JSON.stringify(data, null, 2)
}`
throw new BigcommerceApiError(msg, res, data)
}
if (res.status !== 204 && !isJSON) {
throw new BigcommerceApiError(
`Fetch to Bigcommerce API failed, expected JSON content but found: ${contentType}`,
res
)
}
// If something was removed, the response will be empty
return res.status === 204 ? null : await res.json()
}
function getRawHeaders(res: Response) { function getRawHeaders(res: Response) {
const headers: { [key: string]: string } = {} const headers: { [key: string]: string } = {}