@sp-api-sdk/common
Version:
Selling Parner API common library
101 lines (100 loc) • 4.38 kB
JavaScript
import axios, { isAxiosError } from 'axios';
import { errorLogger, requestLogger, responseLogger } from 'axios-logger';
import axiosRetry from 'axios-retry';
import { SellingPartnerApiAuthError } from '@sp-api-sdk/auth';
import { SellingPartnerApiError } from './errors';
import { sellingPartnerRegions } from './regions';
import { packageJson } from './utils/package';
export function createAxiosInstance({ auth, restrictedDataToken, region, userAgent = `${packageJson.name}/${packageJson.version}`, sandbox = false, rateLimiting, logging, }, rateLimits) {
const regionConfiguration = sellingPartnerRegions[region];
if (!regionConfiguration) {
throw new TypeError(`Unknown or unsupported region: ${region}`);
}
const instance = axios.create({
headers: {
'user-agent': userAgent,
},
});
const endpoint = regionConfiguration.endpoints[sandbox ? 'sandbox' : 'production'];
if (rateLimiting?.retry) {
axiosRetry(instance, {
retryCondition: (error) => error.response?.status === 429,
retryDelay(retryCount, error) {
const url = new URL(error.config.url);
const method = error.config.method?.toLowerCase();
const amznRateLimit = Number.parseFloat(error.response?.headers['x-amzn-ratelimit-limit'] ?? '');
const rateLimit = Number.isNaN(amznRateLimit)
? rateLimits.find((rateLimit) => rateLimit.method.toLowerCase() === method && rateLimit.urlRegex.exec(url.pathname))?.rate
: amznRateLimit;
const delay = rateLimit ? (1 / rateLimit) * 1000 + 1500 : 60 * 1000;
if (rateLimiting.onRetry) {
rateLimiting.onRetry({ delay, rateLimit, retryCount, error });
}
return delay;
},
});
}
// Set x-amz-access-token to each request
instance.interceptors.request.use(async (config) => {
config.headers['x-amz-access-token'] = restrictedDataToken ?? (await auth.getAccessToken());
return config;
});
instance.interceptors.response.use(async (response) => response, async (error) => {
if (isAxiosError(error) && !(error instanceof SellingPartnerApiAuthError)) {
throw new SellingPartnerApiError(error);
}
throw error;
});
if (logging?.request) {
const requestLoggerOptions = logging.request === true ? undefined : logging.request;
if (requestLoggerOptions?.headers) {
console.warn('WARNING: You have enabled logging of request headers, this can leak authentication information, you should disable in production.');
}
instance.interceptors.request.use((config) => {
const logger = requestLogger(config, {
prefixText: `sp-api-sdk/${region}`,
dateFormat: 'isoDateTime',
method: true,
url: true,
params: false,
data: true,
headers: false,
logger: console.info,
...requestLoggerOptions,
});
return {
...logger,
headers: config.headers,
};
});
}
if (logging?.response) {
const responseLoggerOptions = logging.response === true ? undefined : logging.response;
instance.interceptors.response.use((response) => responseLogger(response, {
prefixText: `sp-api-sdk/${region}`,
dateFormat: 'isoDateTime',
status: true,
statusText: false,
params: false,
data: false,
headers: true,
logger: console.info,
...responseLoggerOptions,
}));
}
if (logging?.error) {
const errorLoggerOptions = logging.error === true ? undefined : logging.error;
instance.interceptors.response.use((response) => response, async (error) => errorLogger(error, {
prefixText: `sp-api-sdk/${region}`,
dateFormat: 'isoDateTime',
status: true,
statusText: false,
params: false,
data: false,
headers: true,
logger: console.error,
...errorLoggerOptions,
}));
}
return { axios: instance, endpoint };
}