ebay-api
Version:
eBay API for Node and Browser
178 lines (177 loc) • 6.01 kB
JavaScript
import { EBayInvalidAccessToken, handleEBayError } from '../../errors/index.js';
import Api from '../index.js';
export const defaultApiHeaders = {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
// @ts-ignore
...(typeof window === 'undefined' ? {
'Accept-Encoding': 'application/gzip'
} : {})
};
const additionalHeaders = {
marketplaceId: 'X-EBAY-C-MARKETPLACE-ID',
endUserCtx: 'X-EBAY-C-ENDUSERCTX',
acceptLanguage: 'Accept-Language',
contentLanguage: 'Content-Language',
};
export default class Restful extends Api {
constructor(config, req, auth, apiConfig = {}) {
super(config, req, auth);
this.apiConfig = {
...this.getApiConfig(),
...apiConfig
};
}
static buildServerUrl(schema, subdomain, sandbox, tld) {
return `${schema}${subdomain}.${sandbox ? 'sandbox.' : ''}${tld}`;
}
/**
* Enable to supports the use of OAuth tokens for user authorization.
*/
get useIaf() {
return false;
}
get schema() {
return 'https://';
}
get subdomain() {
return 'api';
}
get apiVersionPath() {
return '';
}
getServerUrl({ schema, subdomain, apiVersion, basePath, sandbox, tld }) {
return Restful.buildServerUrl(schema, subdomain, sandbox, tld) + apiVersion + basePath;
}
getApiConfig() {
return {
subdomain: this.subdomain,
useIaf: this.useIaf,
apiVersion: this.apiVersionPath,
basePath: this.basePath,
schema: this.schema,
sandbox: this.config.sandbox,
tld: 'ebay.com',
headers: {},
returnResponse: false,
sign: false
};
}
get baseUrl() {
return this.getServerUrl(this.apiConfig);
}
/**
* Create a new instances of it self with specified api config.
* @param apiConfig
*/
api(apiConfig) {
// @ts-ignore
return new this.constructor(this.config, this.req, this.auth, apiConfig);
}
/**
* Use "apix" subdomain
*/
get apix() {
return this.api({ subdomain: 'apix' });
}
/**
* Use "apiz" subdomain
*/
get apiz() {
return this.api({ subdomain: 'apiz' });
}
/**
* Sign request
*/
get sign() {
return this.api({ sign: true });
}
async get(path, config = {}, apiConfig) {
return this.doRequest({ method: 'get', path, config }, apiConfig);
}
async delete(path, config = {}, apiConfig) {
return this.doRequest({ method: 'delete', path, config }, apiConfig);
}
async post(path, data, config = {}, apiConfig) {
return this.doRequest({ method: 'post', path, data, config }, apiConfig);
}
async put(path, data, config = {}, apiConfig) {
return this.doRequest({ method: 'put', path, data, config }, apiConfig);
}
get additionalHeaders() {
return Object.keys(additionalHeaders)
// @ts-ignore
.filter(key => typeof this.config[key] !== 'undefined')
.reduce((headers, key) => {
// @ts-ignore
headers[additionalHeaders[key]] = this.config[key];
return headers;
}, {});
}
async enrichRequestConfig(apiRequest, payload = null, apiConfig = this.apiConfig) {
const authHeader = await this.auth.getHeaderAuthorization(apiConfig.useIaf);
const signatureHeaders = apiConfig.sign ? this.getDigitalSignatureHeaders({
method: apiRequest.method.toUpperCase(),
authority: Restful.buildServerUrl('', apiConfig.subdomain, apiConfig.sandbox, apiConfig.tld),
path: apiConfig.apiVersion + apiConfig.basePath + apiRequest.path
}, payload) : {};
const headers = {
...defaultApiHeaders,
...this.additionalHeaders,
...authHeader,
...apiConfig.headers,
...signatureHeaders
};
return {
...apiRequest.config,
headers: {
...(apiRequest.config.headers || {}),
...headers
}
};
}
async doRequest(payload, apiConfig) {
try {
return await this.request(payload, apiConfig);
}
catch (error) {
if (this.shouldRefreshToken(error)) {
// Try again and refresh token
return await this.request(payload, apiConfig, true /* refresh token */);
}
throw error;
}
}
shouldRefreshToken(error) {
if (!this.config.autoRefreshToken) {
return false;
}
if (error.name === EBayInvalidAccessToken.name) {
return true;
}
return error?.meta?.res?.status === 401 && this.apiConfig.basePath === '/post-order/v2';
}
async request(apiRequest, apiConfig = this.apiConfig, refreshToken = false) {
const { path, method, data } = apiRequest;
const apiCfg = { ...this.apiConfig, ...apiConfig };
const endpoint = this.getServerUrl(apiCfg) + path;
try {
if (refreshToken) {
await this.auth.OAuth2.refreshToken();
}
const enrichedConfig = await this.enrichRequestConfig(apiRequest, data, apiCfg);
const args = ['get', 'delete'].includes(method) ? [enrichedConfig] : [data, enrichedConfig];
// @ts-ignore
const response = await this.req[method](endpoint, ...args);
if (this.apiConfig.returnResponse) {
return response;
}
else {
return response.data;
}
}
catch (ex) {
handleEBayError(ex);
}
}
}