UNPKG

lumen-react-javascript

Version:
256 lines (227 loc) 10.6 kB
import {AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, Cancel, default as axios} from 'axios'; import {History} from 'history'; import AuthUtils from './auth-utils'; import * as _ from 'lodash'; import {getGlobal, setGlobal} from './window-utils'; import {makeId} from './string-utils'; import {parseHeadersToApiResponseHeaders} from '..'; export function createCancelToken(id: string, config = null) { let source = makeCancelToken(); storeCancelToken(id, source, config); return source; } export function makeCancelToken() { let source: any = axios.CancelToken.source(); source.id = makeId(); return source; } export function storeCancelToken(id: string, source, config = null) { let storedCancelTokens = getGlobal('storedCancelTokens', []); storedCancelTokens.push({id, source, config}); setGlobal('storedCancelTokens', storedCancelTokens); } export function cancelRequest(tokenOrId: string, message: string = null) { let storedCancelTokens = getGlobal('storedCancelTokens', []); let lastIndex = -1; let sourceIndex = storedCancelTokens.findIndex( s => s.source.id == tokenOrId || s.id == tokenOrId ); while (sourceIndex >= 0) { lastIndex = sourceIndex; storedCancelTokens[sourceIndex].source.cancel( JSON.stringify({id: storedCancelTokens[sourceIndex].id, message})); sourceIndex = storedCancelTokens.findIndex( (s, index) => index > lastIndex && (s.source.id == tokenOrId || s.id == tokenOrId) ); } } export interface AxiosRequestConfigExtended extends AxiosRequestConfig { onResponse?: { [code: number]: () => void }; onExpired?: () => void; skipCancel?: boolean; cancelTokenId?: string; cancelMessage?: string; globalHandlers?: { onRequest?: (config: AxiosRequestConfigExtended, originalConfig: AxiosRequestConfigExtended) => void; onRequestError?: (error: AxiosError, originalConfig: AxiosRequestConfigExtended) => void; onResponse?: (response: AxiosResponse, originalConfig: AxiosRequestConfigExtended) => void; onResponseError?: (error: AxiosError | Cancel, originalConfig: AxiosRequestConfigExtended) => void; } } export function bypassGlobalResponseHandlers(bypassGlobalResponseHandlersOption: (status: number, response: any, expired: boolean) => boolean | boolean | Array<number>, status: number, response: any, expired: boolean) { if (_.isBoolean(bypassGlobalResponseHandlersOption)) { return bypassGlobalResponseHandlersOption; } else if (_.isArray(bypassGlobalResponseHandlersOption)) { return bypassGlobalResponseHandlersOption.findIndex(h => h == status) >= 0; } else { return bypassGlobalResponseHandlersOption(status, response, expired); } } export function setupAxiosInstance(instance: AxiosInstance, config: AxiosRequestConfigExtended = {}) { instance.interceptors.request.use( (_config: AxiosRequestConfigExtended) => { _config = {..._config, ...(config || {})}; let source = makeCancelToken(); let tokenId: string = _config.cancelToken ? _config.cancelToken as any : `${_config.method} ${_config.url}`.toLowerCase(); _config.cancelToken = source.token; _config.cancelTokenId = source.id; if (!(_config as any).skipCancel) { cancelRequest(tokenId, _config.cancelMessage || 'Skipped because of ' + source.id); } if (AuthUtils.isLoggedIn()) { _config.headers = {..._config.headers, ...{token: AuthUtils.getToken()}}; } for (let key in _config.headers) { let header = _config.headers[key]; if (_.isFunction(header)) { _config.headers[key] = header(); } } storeCancelToken(tokenId, source, _config); if (config.globalHandlers && config.globalHandlers.onRequest) { config.globalHandlers.onRequest(_config, config); } return Promise.resolve(_config); }, (error: AxiosError) => { console.error(error); if (config.globalHandlers && config.globalHandlers.onRequest) { config.globalHandlers.onRequestError(error, config); } return Promise.reject(error); } ); instance.interceptors.response.use( (response: AxiosResponse) => { if (response.config.cancelToken) { let storedCancelTokens = getGlobal('storedCancelTokens', []); let index = storedCancelTokens.findIndex(s => s.source.id == (response.config as any).cancelTokenId); if (index >= 0) { storedCancelTokens.splice(index, 1); setGlobal('storedCancelTokens', storedCancelTokens); } } let config: any = (response.config as AxiosRequestConfigExtended); let headers = parseHeadersToApiResponseHeaders(response.headers); let bypass = 'bypassGlobalResponseHandlers' in config && bypassGlobalResponseHandlers(config.bypassGlobalResponseHandlers, response.status, response.data, !!headers.expired); if (!bypass) { if (config.onResponse && response.status in config.onResponse) { config.onResponse[response.status](); } if (headers.expired && config.onExpired) { config.onExpired(); } } if (config.globalHandlers && config.globalHandlers.onResponse) { config.globalHandlers.onResponse(response, config); } return response; }, (error: AxiosError | Cancel) => { if (axios.isCancel(error)) { try { let cancelPayload = JSON.parse((error as Cancel).message); let storedCancelTokens = getGlobal('storedCancelTokens', []); let sourceIndex = storedCancelTokens.findIndex(s => s.id == cancelPayload.id); if (sourceIndex >= 0) { console.warn(cancelPayload.message, storedCancelTokens[sourceIndex]); if (config.globalHandlers && config.globalHandlers.onResponseError) { config.globalHandlers.onResponseError({ message: cancelPayload.message, config: storedCancelTokens[sourceIndex] }, config); } storedCancelTokens.splice(sourceIndex, 1); } else { console.warn(error); if (config.globalHandlers && config.globalHandlers.onResponseError) { config.globalHandlers.onResponseError(error as Cancel, config); } } } catch { console.warn(error); if (config.globalHandlers && config.globalHandlers.onResponseError) { config.globalHandlers.onResponseError(error as Cancel, config); } } } else { if ((error as AxiosError).config.cancelToken) { let storedCancelTokens = getGlobal('storedCancelTokens', []); let index = storedCancelTokens.findIndex(s => s.source.id == (error as any).config.cancelTokenId); if (index >= 0) { storedCancelTokens.splice(index, 1); setGlobal('storedCancelTokens', storedCancelTokens); } } console.log('ERROR RESPONSE', error); let config: any = ((error as AxiosError).config as AxiosRequestConfigExtended); let response = (error as AxiosError).response; let headers = parseHeadersToApiResponseHeaders(response.headers); let bypass = 'bypassGlobalResponseHandlers' in config && bypassGlobalResponseHandlers(config.bypassGlobalResponseHandlers, response.status, response.data, !!headers.expired); if (!bypass) { if (config.onResponse && response.status in config.onResponse) { config.onResponse[response.status](); } if (headers.expired && config.onExpired) { config.onExpired(); } } if (config.globalHandlers && config.globalHandlers.onResponseError) { config.globalHandlers.onResponseError(error as AxiosError, config); } } return Promise.reject(error); } ); } export function redirectOnFailConnect(history: History, redirects = { 401: (history: History) => history.push('/login'), 403: (history: History) => history.push('/login'), 404: (history: History) => history.push('/notfound'), }): { catch: (e: any) => any } { return { catch: redirectOnFail(history, redirects), }; } export function redirectOnFail(history: History, redirects = { 401: (history: History) => history.push('/login'), 403: (history: History) => history.push('/login'), 404: (history: History) => history.push('/notfound'), }): (e: any) => any { return e => { if (e.response && e.response.status && redirects[e.response.status]) { if (e.response.status == 401) { AuthUtils.logout(); setTimeout(() => window.document.location.reload(true), 500); } redirects[e.response.status](history); } }; } export function backOnSuccessConnect(history: History, to = null): { then: (r: any) => any } { return { then: backOnSuccess(history, to), }; } export function backOnSuccess(history: History, to = null): (r: any) => any { return response => { if (to) { history.push(to); } else { history.goBack(); } }; }