<% const { apiConfig, generateResponses, config } = it; %> import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType } from "axios"; export type QueryParamsType = Record<string | number, any>; export interface FullRequestParams extends Omit<AxiosRequestConfig, "data" | "params" | "url" | "responseType"> { /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; /** request path */ path: string; /** content type of request body */ type?: ContentType; /** query params */ query?: QueryParamsType; /** format of response (i.e. response.json() -> format: "json") */ format?: ResponseType; /** wrapped response */ wrapped?: boolean; /** request body */ body?: unknown; } export type RequestParams = Omit<FullRequestParams, "body" | "method" | "path">; export interface ApiConfig<SecurityDataType = unknown> extends Omit<AxiosRequestConfig, "data" | "cancelToken"> { securityWorker?: (securityData: SecurityDataType | null) => Promise<AxiosRequestConfig | void> | AxiosRequestConfig | void; secure?: boolean; format?: ResponseType; } export enum ContentType { Json = "application/json", FormData = "multipart/form-data", UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient<SecurityDataType = unknown> { public instance: AxiosInstance; private securityData: SecurityDataType | null = null; private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"]; private secure?: boolean; private format?: ResponseType; constructor({ securityWorker, secure, format, ...axiosConfig }: ApiConfig<SecurityDataType> = {}) { this.instance = axios.create({ ...axiosConfig, baseURL: axiosConfig.baseURL || "<%~ apiConfig.baseUrl %>" }) this.secure = secure; this.format = format; this.securityWorker = securityWorker; } public setSecurityData = (data: SecurityDataType | null) => { this.securityData = data } private mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig): AxiosRequestConfig { return { ...this.instance.defaults, ...params1, ...(params2 || {}), headers: { ...(this.instance.defaults.headers || {}), ...(params1.headers || {}), ...((params2 && params2.headers) || {}), }, }; } protected createFormData(input: Record<string, unknown>): FormData { if (input instanceof FormData) { return input; } return Object.keys(input || {}).reduce((formData, key) => { const property = input[key]; if (property instanceof Blob) { formData.append(key, property) } else if (typeof property === 'object' && property !== null) { if (Array.isArray(property)) { // eslint-disable-next-line functional/no-loop-statement for (const prop of property) { formData.append(`${key}[]`, prop) } } else { formData.append(key, JSON.stringify(property)) } } else { formData.append(key, `${property}`) } return formData; }, new FormData()); } public request = async <T = any, _E = any>({ secure, path, type, query, format, wrapped, body, ...params <% if (config.unwrapResponseData) { %> }: FullRequestParams): Promise<T> => { <% } else { %> }: FullRequestParams): Promise<AxiosResponse<T>> => { <% } %> const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {}; const requestParams = this.mergeRequestParams(params, secureParams); const responseFormat = (format && this.format) || void 0; if (type === ContentType.FormData && body && body !== null && typeof body === "object") { requestParams.headers.common = { Accept: "*/*" }; requestParams.headers.post = {}; requestParams.headers.put = {}; body = this.createFormData(body as Record<string, unknown>); } return this.instance.request({ ...requestParams, headers: { ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}), ...(requestParams.headers || {}), }, params: query, responseType: responseFormat, data: body, url: path, <% if (config.unwrapResponseData) { %> }).then(response => { if(wrapped) return response; return response.data; }); <% } else { %> }); <% } %> }; }