153 lines
3.7 KiB
JavaScript
153 lines
3.7 KiB
JavaScript
/* global axios */
|
|
|
|
const DEFAULT_API_VERSION = 'v1';
|
|
const DEFAULT_OPTIONS = {
|
|
apiVersion: DEFAULT_API_VERSION,
|
|
enterprise: false,
|
|
accountScoped: false,
|
|
cancelPreviousRequests: false,
|
|
};
|
|
|
|
class ApiClient {
|
|
constructor(resource, options = {}) {
|
|
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
this.apiVersion = `/api/${this.options.apiVersion}`;
|
|
this.resource = resource;
|
|
this.abortControllers = new Map();
|
|
this.activeRequests = new Map();
|
|
}
|
|
|
|
get url() {
|
|
return `${this.baseUrl()}/${this.resource}`;
|
|
}
|
|
|
|
// eslint-disable-next-line class-methods-use-this
|
|
get accountIdFromRoute() {
|
|
const isInsideAccountScopedURLs =
|
|
window.location.pathname.includes('/app/accounts');
|
|
|
|
if (isInsideAccountScopedURLs) {
|
|
return window.location.pathname.split('/')[3];
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
baseUrl() {
|
|
let url = this.apiVersion;
|
|
|
|
if (this.options.enterprise) {
|
|
url = `/enterprise${url}`;
|
|
}
|
|
|
|
if (this.options.accountScoped && this.accountIdFromRoute) {
|
|
url = `${url}/accounts/${this.accountIdFromRoute}`;
|
|
}
|
|
|
|
return url;
|
|
}
|
|
|
|
generateRequestKey(method, id = '', customRequestKey = '') {
|
|
if (customRequestKey) return customRequestKey;
|
|
return `${method}-${this.url}${id ? `/${id}` : ''}`;
|
|
}
|
|
|
|
cancelRequest(requestKey) {
|
|
const controller = this.abortControllers.get(requestKey);
|
|
if (controller) {
|
|
controller.abort();
|
|
this.abortControllers.delete(requestKey);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
setupRequest(method, options = {}) {
|
|
if (!this.options.cancelPreviousRequests) {
|
|
return {};
|
|
}
|
|
const { id, customRequestKey } = options;
|
|
const requestKey = this.generateRequestKey(method, id, customRequestKey);
|
|
|
|
const previousRequests = this.activeRequests.get(method) || [];
|
|
const remainingRequests = previousRequests.filter(key => {
|
|
if (key === requestKey) {
|
|
this.cancelRequest(key);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
this.activeRequests.set(method, [...remainingRequests, requestKey]);
|
|
|
|
const controller = new AbortController();
|
|
this.abortControllers.set(requestKey, controller);
|
|
|
|
return { requestKey, signal: controller.signal };
|
|
}
|
|
|
|
async request(method, config = {}) {
|
|
const { id, data, customRequestKey, ...axiosConfig } = config;
|
|
const { requestKey, signal } = this.setupRequest(method, {
|
|
id,
|
|
customRequestKey,
|
|
});
|
|
try {
|
|
const url = id ? `${this.url}/${id}` : this.url;
|
|
return await axios({
|
|
method,
|
|
url,
|
|
data,
|
|
signal,
|
|
...axiosConfig,
|
|
});
|
|
} finally {
|
|
this.abortControllers.delete(requestKey);
|
|
if (this.options.cancelPreviousRequests) {
|
|
const methodRequests = this.activeRequests.get(method) || [];
|
|
this.activeRequests.set(
|
|
method,
|
|
methodRequests.filter(key => key !== requestKey)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
get(config = {}) {
|
|
return this.request('GET', config);
|
|
}
|
|
|
|
show(id, config = {}) {
|
|
return this.request('GET', { ...config, id });
|
|
}
|
|
|
|
create(data, config = {}) {
|
|
return this.request('POST', { ...config, data });
|
|
}
|
|
|
|
update(id, data, config = {}) {
|
|
return this.request('PATCH', { ...config, id, data });
|
|
}
|
|
|
|
delete(id, config = {}) {
|
|
return this.request('DELETE', { ...config, id });
|
|
}
|
|
|
|
cancelAllRequests() {
|
|
this.abortControllers.forEach(controller => controller.abort());
|
|
this.abortControllers.clear();
|
|
this.activeRequests.clear();
|
|
}
|
|
|
|
// Get all active request keys
|
|
getActiveRequests() {
|
|
return Array.from(this.abortControllers.keys());
|
|
}
|
|
|
|
destroy() {
|
|
this.cancelAllRequests();
|
|
}
|
|
}
|
|
|
|
export default ApiClient;
|