mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
4.8 KiB
145 lines
4.8 KiB
<% |
|
const { apiConfig, generateResponses, config } = it; |
|
%> |
|
|
|
import type { AxiosInstance, AxiosRequestConfig, HeadersDefaults, ResponseType, AxiosResponse } from "axios"; |
|
import axios 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" | "query" | "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", |
|
Text = "text/plain", |
|
} |
|
|
|
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 |
|
} |
|
|
|
protected mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig): AxiosRequestConfig { |
|
const method = params1.method || (params2 && params2.method) |
|
|
|
return { |
|
...this.instance.defaults, |
|
...params1, |
|
...(params2 || {}), |
|
headers: { |
|
...((method && this.instance.defaults.headers[method.toLowerCase() as keyof HeadersDefaults]) || {}), |
|
...(params1.headers || {}), |
|
...((params2 && params2.headers) || {}), |
|
}, |
|
}; |
|
} |
|
|
|
protected stringifyFormItem(formItem: unknown) { |
|
if (typeof formItem === "object" && formItem !== null) { |
|
return JSON.stringify(formItem); |
|
} else { |
|
return `${formItem}`; |
|
} |
|
} |
|
|
|
protected createFormData(input: Record<string, unknown>): FormData { |
|
return Object.keys(input || {}).reduce((formData, key) => { |
|
const property = input[key]; |
|
const propertyContent: any[] = (property instanceof Array) ? property : [property] |
|
|
|
for (const formItem of propertyContent) { |
|
const isFileType = formItem instanceof Blob || formItem instanceof File; |
|
formData.append( |
|
key, |
|
isFileType ? formItem : this.stringifyFormItem(formItem) |
|
); |
|
} |
|
|
|
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) || undefined; |
|
|
|
if (type === ContentType.FormData && body && body !== null && typeof body === "object") { |
|
body = this.createFormData(body as Record<string, unknown>); |
|
} |
|
|
|
if (type === ContentType.Text && body && body !== null && typeof body !== "string") { |
|
body = JSON.stringify(body); |
|
} |
|
|
|
return this.instance.request({ |
|
...requestParams, |
|
headers: { |
|
...(requestParams.headers || {}), |
|
...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}), |
|
}, |
|
params: query, |
|
responseType: responseFormat, |
|
data: body, |
|
url: path, |
|
<% if (config.unwrapResponseData) { %> |
|
}).then(response => { |
|
if(wrapped) return response; |
|
return response.data; |
|
}); |
|
<% } else { %> |
|
}); |
|
<% } %> |
|
}; |
|
} |