UNPKG

@kubb/plugin-client

Version:

API client generator plugin for Kubb, creating type-safe HTTP clients (Axios, Fetch) from OpenAPI specifications for making API requests.

98 lines (79 loc) 2.8 kB
/** * RequestCredentials */ export type RequestCredentials = 'omit' | 'same-origin' | 'include' /** * Subset of FetchRequestConfig */ export type RequestConfig<TData = unknown> = { baseURL?: string url?: string method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' params?: unknown data?: TData | FormData responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream' signal?: AbortSignal headers?: [string, string][] | Record<string, string> credentials?: RequestCredentials } /** * Subset of FetchResponse */ export type ResponseConfig<TData = unknown> = { data: TData status: number statusText: string headers: Headers } let _config: Partial<RequestConfig> = {} export const getConfig = () => _config export const setConfig = (config: Partial<RequestConfig>) => { _config = config return getConfig() } export const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => { return configs.reduce<Partial<T>>((merged, config) => { return { ...merged, ...config, headers: { ...(Array.isArray(merged.headers) ? Object.fromEntries(merged.headers) : merged.headers), ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers), }, } }, {}) } export type ResponseErrorConfig<TError = unknown> = TError export type Client = <TResponseData, _TError = unknown, TRequestData = unknown>(config: RequestConfig<TRequestData>) => Promise<ResponseConfig<TResponseData>> export const client = async <TResponseData, _TError = unknown, RequestData = unknown>( paramsConfig: RequestConfig<RequestData>, ): Promise<ResponseConfig<TResponseData>> => { const normalizedParams = new URLSearchParams() const config = mergeConfig(getConfig(), paramsConfig) Object.entries(config.params || {}).forEach(([key, value]) => { if (value !== undefined) { normalizedParams.append(key, value === null ? 'null' : value.toString()) } }) let targetUrl = [config.baseURL, config.url].filter(Boolean).join('') if (config.params) { targetUrl += `?${normalizedParams}` } const response = await fetch(targetUrl, { credentials: config.credentials || 'same-origin', method: config.method?.toUpperCase(), body: config.data instanceof FormData ? config.data : JSON.stringify(config.data), signal: config.signal, headers: config.headers, }) const data = [204, 205, 304].includes(response.status) || !response.body ? {} : await response.json() return { data: data as TResponseData, status: response.status, statusText: response.statusText, headers: response.headers as Headers, } } client.getConfig = getConfig client.setConfig = setConfig export default client