tickethead-sdk
Version:
SDK for the Tickethead API
145 lines • 7.61 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseUrl = void 0;
exports.createBaseUrl = createBaseUrl;
exports.setAxiosUpdateTokenFunction = setAxiosUpdateTokenFunction;
exports.nopUpdate = nopUpdate;
exports.buildClient = buildClient;
const axios_retry_1 = __importDefault(require("axios-retry"));
const axios_cache_interceptor_1 = require("axios-cache-interceptor");
const axios_1 = __importDefault(require("axios"));
const converter_1 = require("./converter");
const errors_1 = require("./errors");
// Constants
var BaseUrl;
(function (BaseUrl) {
BaseUrl["ThProd"] = "https://api.tickethead.io";
BaseUrl["ThStaging"] = "https://api.staging.tickethead.io";
})(BaseUrl || (exports.BaseUrl = BaseUrl = {}));
function createBaseUrl(baseUrl = BaseUrl.ThProd, tenantName = undefined) {
var _a;
const [protocol, base] = baseUrl.split('://');
return `${protocol}://${(_a = tenantName === null || tenantName === void 0 ? void 0 : tenantName.concat('.')) !== null && _a !== void 0 ? _a : ''}${base}`;
}
/**
* Sets the update request strategy for an axios instance
*/
function setAxiosUpdateTokenFunction(instance, updateToken) {
;
instance.updateToken = updateToken;
}
/**
* Does nothing. Will cause 401 requests to fail as usual.
*/
function nopUpdate() {
return __awaiter(this, void 0, void 0, function* () {
return '';
});
}
/**
* Builds an API client object. By default, creates a production client with cluster-wide access.
* If `tenantName` is specified, the client includes the tenant name in the URL.
*
* @param baseUrl Base URL of the REST API (default: PROD_BASE_URL)
* @param tenantName Tenant name (defaults to undefined)
* @param retryOptions Configuration for the retry policy
* @param cacheOptions Configuration for caching, by default no caching is done
* @returns axios.AxiosInstance
*/
function buildClient({ baseUrl = BaseUrl.ThProd, tenantName, retryOptions = { retries: 3 }, cacheOptions, camelCaseResponse, }) {
const axiosOptions = {
baseURL: createBaseUrl(baseUrl, tenantName),
};
let instance = axios_1.default.create(axiosOptions);
if (cacheOptions) {
instance = (0, axios_cache_interceptor_1.setupCache)(instance, cacheOptions);
}
// Add a retry mechanism to all requests
(0, axios_retry_1.default)(instance, retryOptions);
instance.defaults.headers.post['Content-Type'] = 'application/json';
instance.defaults.headers.patch['Content-Type'] = 'application/json';
instance.defaults.headers.put['Content-Type'] = 'application/json';
// Sets the token update strategy
setAxiosUpdateTokenFunction(instance, nopUpdate);
// TODO: Add expiration check and update the token if needed
instance.interceptors.request.use(function (config) {
if (!config.headers['Content-Type'] ||
config.headers['Content-Type'] === 'application/json') {
config.data = (0, converter_1.stringifyDates)((0, converter_1.toSnakeCase)(config.data));
}
return config;
}, function (error) {
Promise.reject(error);
});
instance.interceptors.response.use(function (response) {
// If there is no need to convert case
if (!camelCaseResponse ||
['stream', 'blob', 'arraybuffer'].includes(response.config.responseType)) {
return response;
}
return Object.assign(Object.assign({}, response), { data: (0, converter_1.parseDates)((0, converter_1.toCamelCase)(response.data)) });
}, function (error) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
// Reject promise if usual error or it has been retried
if (((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) !== 401 || ((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.config._retry)) {
// error.response.config._retry = false
return Promise.reject(errorBuilder(error));
}
// When response code is 401, try to refresh the token.
try {
// BEWARE of hack
// Added updateToken function to axios instance because removing an interceptor is very hard
// It enables changing of the token updating strategy on the fly
const token = yield instance.updateToken();
// Sets the retry flag
error.response.config._retry = true;
error.response.config.headers['Authorization'] = 'Bearer ' + token;
return yield instance(error.response.config);
}
catch (err) {
return Promise.reject(errorBuilder(error));
}
});
});
return instance;
}
/**
* Builds a error instance based on the response HTTP status code
*
* @param error Error response from axios instance
* @returns Error implementation
*/
function errorBuilder(error) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
// The error is sometimes an error object and sometimes an axios error
const message = (_d = (_c = (_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) !== null && _c !== void 0 ? _c : error.message) !== null && _d !== void 0 ? _d : 'Error in response from service';
const errorCode = ((_f = (_e = error.response) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.errorCode) ||
((_h = (_g = error.response) === null || _g === void 0 ? void 0 : _g.data) === null || _h === void 0 ? void 0 : _h.error) ||
error.error ||
'Error in response from service';
const status = ((_j = error.response) === null || _j === void 0 ? void 0 : _j.status) || error.statusCode || error.status;
let url = error === null || error === void 0 ? void 0 : error.url;
if ((_k = error.config) === null || _k === void 0 ? void 0 : _k.baseURL) {
url = `${(_l = error.config) === null || _l === void 0 ? void 0 : _l.baseURL}/${(_m = error.config) === null || _m === void 0 ? void 0 : _m.url}`;
}
const method = (_p = (_o = error.config) === null || _o === void 0 ? void 0 : _o.method) !== null && _p !== void 0 ? _p : error === null || error === void 0 ? void 0 : error.method;
const data = (_q = error.config) === null || _q === void 0 ? void 0 : _q.data;
if (status) {
return new errors_1.ApiError(message, errorCode, status, url, method, data);
}
return new errors_1.ApiError(message, JSON.stringify(error), status, url, method, data);
}
//# sourceMappingURL=index.js.map