UNPKG

@cmk/fe_utils

Version:
179 lines (161 loc) 4.95 kB
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios' /** Definitions and Types */ /** ********************** */ /** HTTP Query method + 2 custom Response types with File (response=blob) */ export enum QUERY_METHOD { GET = 'GET', POST = 'POST', PUT = 'PUT', DELETE = 'DELETE', GET_FILE = 'GET_FILE', // GET with responseType: 'blob' POST_GET_FILE = 'POST_GET_FILE', // POST with responseType: 'blob' PATCH = 'PATCH', } /** initial timeouts per method */ enum QUERY_TIMEOUT { POST = 1000 * 60 * 2, POST_GET_FILE = 1000 * 60 * 5, GET = 1000 * 60 * 2, GET_FILE = 1000 * 60 * 5, PUT = 1000 * 60 * 2, DELETE = 1000 * 60 * 2, PATCH = 1000 * 60 * 2, } /** Unknown Query Payload */ export type UnknownQueryPayloadType = Record<string, unknown> /** AxiosConfig with some minor adjustments */ export type QueryConfigType = Omit< AxiosRequestConfig, 'data' | 'url' | 'method' > & { disableRedirectToLogin?: boolean } export type QueryParamType<PayloadType> = QueryConfigType & { url: string payload?: PayloadType } /** The type of the query functions */ export type QueryFnType< PayloadType = UnknownQueryPayloadType, ResponseType = unknown, > = ( params: QueryParamType<PayloadType> ) => Promise<AxiosResponse<ResponseType>> export type QueryResponseType<ResponseType = unknown> = { data: ResponseType | null status: number | string statusText: string headers: Record<string, string> error?: unknown } /** utilities for queries */ /** ******************* */ /** Get the content-type header for the payload based on payload (formData -> multipart/form-data)*/ const getContentHeader = (payload: unknown) => { const contentType = payload && payload instanceof FormData ? 'multipart/form-data' : 'application/json' const contentHeader = { 'Content-Type': contentType } return contentHeader } /** utility to merge external and default headers */ const getHeaders = ( payload: unknown, queryHeaders?: AxiosRequestConfig['headers'] ) => { return { ...getContentHeader(payload), ...(queryHeaders ?? {}), } } /** utility to prepare the axios config object for the queries (all methods) */ const makeAxiosQueryConfig = <PayloadType>( method: QUERY_METHOD, params: QueryParamType<PayloadType> ) => { // const const { url, headers: queryHeaders, payload, ...queryConfig } = params const headers: AxiosRequestConfig['headers'] = getHeaders( payload, queryHeaders ) const responseTypeInjection = method === QUERY_METHOD.GET_FILE || method === QUERY_METHOD.POST_GET_FILE ? { responseType: 'blob' as const } : {} const methodLower = method.toLowerCase() const methodAdj = methodLower.includes('post') ? 'post' : methodLower.includes('get') ? 'get' : methodLower.includes('put') ? 'put' : methodLower.includes('delete') ? 'delete' : methodLower.includes('patch') ? 'patch' : 'get' const axiosQueryConfig: AxiosRequestConfig = { timeout: QUERY_TIMEOUT[method], ...queryConfig, data: payload, method: methodAdj, headers, url, ...responseTypeInjection, } return axiosQueryConfig } /** the raw query for all methods */ const genericMethodQuery = async < PayloadType = UnknownQueryPayloadType, ResponseType = unknown, >( method: QUERY_METHOD, params: QueryParamType<PayloadType> ): ReturnType<QueryFnType<PayloadType, ResponseType>> => { const axiosQueryConfig = makeAxiosQueryConfig(method, params) const response = axios(axiosQueryConfig) return response } /** the query for all methods */ export const query = async <PayloadType = unknown, ResponseType = unknown>( method: QUERY_METHOD, params: QueryParamType<PayloadType> ): Promise<QueryResponseType<ResponseType>> => { try { const res = await genericMethodQuery<PayloadType, ResponseType>( method, params ) const response = { data: res.data, status: res.status, statusText: res.statusText, headers: res?.headers as Record<string, string>, } return response } catch (e) { const error: AxiosError = e as AxiosError const axiosResponse: AxiosError['response'] | null = (axios.isAxiosError(e) ? error?.response : error?.response) ?? null const altErrorCode = (typeof e === 'object' && !!e && 'code' in e && (e?.code as string)) || null const altMessage = (typeof e === 'object' && !!e && 'message' in e && (e?.message as string)) || null const response = { data: (e as AxiosError<ResponseType>)?.response?.data ?? null, error: e, status: axiosResponse?.status ?? altErrorCode ?? 'unknown', statusText: axiosResponse?.statusText ?? altMessage ?? 'unknown', headers: (axiosResponse?.headers as Record<string, string>) ?? {}, } return response } }