Update Spree SDK fetcher

This commit is contained in:
tniezg 2021-08-18 15:47:11 +02:00
parent 30c29f0da8
commit 3b3a181dac
4 changed files with 97 additions and 87 deletions

View File

@ -11,7 +11,7 @@ import getSpreeSdkMethodFromEndpointPath from 'framework/spree/utils/getSpreeSdk
import { SpreeSdkVariables } from 'framework/spree/types' import { SpreeSdkVariables } from 'framework/spree/types'
import SpreeSdkMethodFromEndpointPathError from 'framework/spree/errors/SpreeSdkMethodFromEndpointPathError' import SpreeSdkMethodFromEndpointPathError from 'framework/spree/errors/SpreeSdkMethodFromEndpointPathError'
import { GraphQLFetcher, GraphQLFetcherResult } from '@commerce/api' import { GraphQLFetcher, GraphQLFetcherResult } from '@commerce/api'
import createCreateFetchFetcher from '../../utils/createCreateFetchFetcher' import createCustomizedFetchFetcher from '../../utils/createCustomizedFetchFetcher'
import fetch, { Request } from 'node-fetch' import fetch, { Request } from 'node-fetch'
const createApiFetch: ( const createApiFetch: (
@ -22,10 +22,13 @@ const createApiFetch: (
const client = makeClient({ const client = makeClient({
host: requireConfigValue('spreeApiHost') as string, host: requireConfigValue('spreeApiHost') as string,
fetcherType: 'custom', fetcherType: 'custom',
createFetcher: createCreateFetchFetcher({ createFetcher: (fetcherOptions) => {
fetch, return createCustomizedFetchFetcher({
requestClass: Request, fetch,
}), requestConstructor: Request,
...fetcherOptions,
})
},
}) })
return async (url, queryData = {}, fetchOptions = {}) => { return async (url, queryData = {}, fetchOptions = {}) => {

View File

@ -12,15 +12,18 @@ import getSpreeSdkMethodFromEndpointPath from './utils/getSpreeSdkMethodFromEndp
import SpreeSdkMethodFromEndpointPathError from './errors/SpreeSdkMethodFromEndpointPathError' import SpreeSdkMethodFromEndpointPathError from './errors/SpreeSdkMethodFromEndpointPathError'
import type { SpreeSdkVariables } from './types' import type { SpreeSdkVariables } from './types'
import type { GraphQLFetcherResult } from '@commerce/api' import type { GraphQLFetcherResult } from '@commerce/api'
import createCreateFetchFetcher from './utils/createCreateFetchFetcher' import createCustomizedFetchFetcher from './utils/createCustomizedFetchFetcher'
const client = makeClient({ const client = makeClient({
host: requireConfigValue('spreeApiHost') as string, host: requireConfigValue('spreeApiHost') as string,
fetcherType: 'custom', fetcherType: 'custom',
createFetcher: createCreateFetchFetcher({ createFetcher: (fetcherOptions) => {
fetch: globalThis.fetch, return createCustomizedFetchFetcher({
requestClass: globalThis.Request, fetch: globalThis.fetch,
}), requestConstructor: globalThis.Request,
...fetcherOptions,
})
},
}) })
const fetcher: Fetcher< const fetcher: Fetcher<

View File

@ -1,77 +0,0 @@
import * as qs from 'qs'
import { errors } from '@spree/storefront-api-v2-sdk'
import type { CreateFetcher } from '@spree/storefront-api-v2-sdk/types/interfaces/ClientConfig'
const createCreateFetchFetcher =
({ fetch: rawFetch, requestClass }): CreateFetcher =>
// TODO: Fix rawFetch any type.
(fetcherOptions) => {
const { FetchError } = errors
const sharedHeaders = {
'Content-Type': 'application/json',
}
return {
fetch: async (fetchOptions) => {
// This fetcher always returns request equal null,
// because @vercel/fetch doesn't accept a Request object as argument
// and it's not used by NJC anyway.
try {
const { url, params, method, headers } = fetchOptions
const absoluteUrl = new URL(url, fetcherOptions.host)
let payload
switch (method.toUpperCase()) {
case 'PUT':
case 'POST':
case 'DELETE':
case 'PATCH':
payload = { body: JSON.stringify(params) }
break
default:
payload = null
absoluteUrl.search = qs.stringify(params, {
arrayFormat: 'brackets',
})
}
const request: Request = new requestClass(absoluteUrl.toString(), {
method: method.toUpperCase(),
headers: { ...sharedHeaders, ...headers },
...payload,
})
try {
const response: Response = await rawFetch(request)
const data = await response.json()
if (!response.ok) {
// Use the "traditional" approach and reject non 2xx responses.
throw new FetchError(response, request, data)
}
return {
// Add response key to the prototype so it can be passed inside the GraphQLFetcherResult type.
// TODO: Search for a better solution than adding response to the prototype.
data: Object.setPrototypeOf({ data }, { response }),
}
} catch (error) {
if (error instanceof TypeError) {
throw new FetchError(null, request, null)
}
throw error
}
} catch (error) {
if (error instanceof FetchError) {
throw error
}
throw new FetchError(null, null, null, error.message)
}
},
}
}
export default createCreateFetchFetcher

View File

@ -0,0 +1,81 @@
import * as qs from 'qs'
import { errors } from '@spree/storefront-api-v2-sdk'
import type { CreateCustomizedFetchFetcher } from '@spree/storefront-api-v2-sdk/types/interfaces/CreateCustomizedFetchFetcher'
const createCustomizedFetchFetcher: CreateCustomizedFetchFetcher = (
fetcherOptions
) => {
const { FetchError } = errors
const sharedHeaders = {
'Content-Type': 'application/json',
}
const { host, fetch, requestConstructor } = fetcherOptions
return {
fetch: async (fetchOptions) => {
// This fetcher always returns request equal null,
// because @vercel/fetch doesn't accept a Request object as argument
// and it's not used by NJC anyway.
try {
const { url, params, method, headers } = fetchOptions
const absoluteUrl = new URL(url, host)
let payload
switch (method.toUpperCase()) {
case 'PUT':
case 'POST':
case 'DELETE':
case 'PATCH':
payload = { body: JSON.stringify(params) }
break
default:
payload = null
absoluteUrl.search = qs.stringify(params, {
arrayFormat: 'brackets',
})
}
const request: Request = new requestConstructor(
absoluteUrl.toString(),
{
method: method.toUpperCase(),
headers: { ...sharedHeaders, ...headers },
...payload,
}
)
try {
const response: Response = await fetch(request)
const data = await response.json()
if (!response.ok) {
// Use the "traditional" approach and reject non 2xx responses.
throw new FetchError(response, request, data)
}
return {
// Add response key to the prototype so it can be passed inside the GraphQLFetcherResult type.
// TODO: Search for a better solution than adding response to the prototype.
data: Object.setPrototypeOf({ data }, { response }),
}
} catch (error) {
if (error instanceof TypeError) {
throw new FetchError(null, request, null)
}
throw error
}
} catch (error) {
if (error instanceof FetchError) {
throw error
}
throw new FetchError(null, null, null, error.message)
}
},
}
}
export default createCustomizedFetchFetcher