| 
 | 1 | +<%  | 
 | 2 | +const { apiConfig, generateResponses, config } = it;  | 
 | 3 | +%>  | 
 | 4 | + | 
 | 5 | +import type { KyInstance, Options as KyOptions, KyResponse } from "ky";  | 
 | 6 | +import ky from "ky";  | 
 | 7 | + | 
 | 8 | +export type QueryParamsType = Record<string | number, any>;  | 
 | 9 | +export type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;  | 
 | 10 | + | 
 | 11 | +export interface FullRequestParams extends Omit<KyOptions, "json" | "body"> {  | 
 | 12 | +  /** set parameter to `true` for call `securityWorker` for this request */  | 
 | 13 | +  secure?: boolean;  | 
 | 14 | +  /** request path */  | 
 | 15 | +  path: string;  | 
 | 16 | +  /** content type of request body */  | 
 | 17 | +  type?: ContentType;  | 
 | 18 | +  /** query params */  | 
 | 19 | +  query?: QueryParamsType;  | 
 | 20 | +  /** format of response (i.e. response.json() -> format: "json") */  | 
 | 21 | +  format?: ResponseFormat;  | 
 | 22 | +  /** request body */  | 
 | 23 | +  body?: unknown;  | 
 | 24 | +}  | 
 | 25 | + | 
 | 26 | +export type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">;  | 
 | 27 | + | 
 | 28 | +export interface ApiConfig<SecurityDataType = unknown> extends Omit<KyOptions, "data" | "cancelToken"> {  | 
 | 29 | +  securityWorker?: (securityData: SecurityDataType | null) => Promise<KyOptions | void> | KyOptions | void;  | 
 | 30 | +  secure?: boolean;  | 
 | 31 | +  format?: ResponseType;  | 
 | 32 | +}  | 
 | 33 | + | 
 | 34 | +export enum ContentType {  | 
 | 35 | +  Json = "application/json",  | 
 | 36 | +  FormData = "multipart/form-data",  | 
 | 37 | +  UrlEncoded = "application/x-www-form-urlencoded",  | 
 | 38 | +  Text = "text/plain",  | 
 | 39 | +}  | 
 | 40 | + | 
 | 41 | +export class HttpClient<SecurityDataType = unknown> {  | 
 | 42 | +    public instance: KyInstance;  | 
 | 43 | +    private securityData: SecurityDataType | null = null;  | 
 | 44 | +    private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];  | 
 | 45 | +    private secure?: boolean;  | 
 | 46 | +    private format?: ResponseType;  | 
 | 47 | + | 
 | 48 | +    constructor({ securityWorker, secure, format, ...options }: ApiConfig<SecurityDataType> = {}) {  | 
 | 49 | +        this.instance = axios.create({ ...options, prefixUrl: options.prefixUrl || "<%~ apiConfig.baseUrl %>" })  | 
 | 50 | +        this.secure = secure;  | 
 | 51 | +        this.format = format;  | 
 | 52 | +        this.securityWorker = securityWorker;  | 
 | 53 | +    }  | 
 | 54 | + | 
 | 55 | +    public setSecurityData = (data: SecurityDataType | null) => {  | 
 | 56 | +        this.securityData = data  | 
 | 57 | +    }  | 
 | 58 | + | 
 | 59 | +    protected mergeRequestParams(params1: KyOptions, params2?: KyOptions): KyOptions {  | 
 | 60 | +      return {  | 
 | 61 | +        ...params1,  | 
 | 62 | +        ...params2,  | 
 | 63 | +        headers: {  | 
 | 64 | +          ...(params1.headers),  | 
 | 65 | +          ...(params2 && params2.headers),  | 
 | 66 | +        },  | 
 | 67 | +      };  | 
 | 68 | +    }  | 
 | 69 | + | 
 | 70 | +    protected stringifyFormItem(formItem: unknown) {  | 
 | 71 | +      if (typeof formItem === "object" && formItem !== null) {  | 
 | 72 | +        return JSON.stringify(formItem);  | 
 | 73 | +      } else {  | 
 | 74 | +        return `${formItem}`;  | 
 | 75 | +      }  | 
 | 76 | +    }  | 
 | 77 | + | 
 | 78 | +    protected createFormData(input: Record<string, unknown>): FormData {  | 
 | 79 | +      return Object.keys(input || {}).reduce((formData, key) => {  | 
 | 80 | +        const property = input[key];  | 
 | 81 | +        const propertyContent: any[] = (property instanceof Array) ? property : [property]  | 
 | 82 | + | 
 | 83 | +        for (const formItem of propertyContent) {  | 
 | 84 | +          const isFileType = formItem instanceof Blob || formItem instanceof File;  | 
 | 85 | +          formData.append(  | 
 | 86 | +            key,  | 
 | 87 | +            isFileType ? formItem : this.stringifyFormItem(formItem)  | 
 | 88 | +            );  | 
 | 89 | +        }  | 
 | 90 | + | 
 | 91 | +        return formData;  | 
 | 92 | +      }, new FormData());  | 
 | 93 | +    }  | 
 | 94 | + | 
 | 95 | +    public request = async <T = any, _E = any>({  | 
 | 96 | +        secure,  | 
 | 97 | +        path,  | 
 | 98 | +        type,  | 
 | 99 | +        query,  | 
 | 100 | +        format,  | 
 | 101 | +        body,  | 
 | 102 | +        ...params  | 
 | 103 | +<% if (config.unwrapResponseData) { %>  | 
 | 104 | +    }: FullRequestParams): Promise<T> => {  | 
 | 105 | +<% } else { %>  | 
 | 106 | +    }: FullRequestParams): KyResponse<T> => {  | 
 | 107 | +<% } %>  | 
 | 108 | +        const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {};  | 
 | 109 | +        const requestParams = this.mergeRequestParams(params, secureParams);  | 
 | 110 | +        const responseFormat = (format || this.format) || undefined;  | 
 | 111 | + | 
 | 112 | +        if (type === ContentType.FormData && body && body !== null && typeof body === "object") {  | 
 | 113 | +          body = this.createFormData(body as Record<string, unknown>);  | 
 | 114 | +        }  | 
 | 115 | + | 
 | 116 | +        if (type === ContentType.Text && body && body !== null && typeof body !== "string") {  | 
 | 117 | +          body = JSON.stringify(body);  | 
 | 118 | +        }  | 
 | 119 | + | 
 | 120 | +        return this.instance.request({  | 
 | 121 | +            ...requestParams,  | 
 | 122 | +            headers: {  | 
 | 123 | +                ...(requestParams.headers || {}),  | 
 | 124 | +                ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}),  | 
 | 125 | +            },  | 
 | 126 | +            params: query,  | 
 | 127 | +            responseType: responseFormat,  | 
 | 128 | +            data: body,  | 
 | 129 | +            url: path,  | 
 | 130 | +<% if (config.unwrapResponseData) { %>  | 
 | 131 | +        }).json();  | 
 | 132 | +<% } else { %>  | 
 | 133 | +        });  | 
 | 134 | +<% } %>  | 
 | 135 | +    };  | 
 | 136 | +}  | 
0 commit comments