UNPKG

@hey-api/openapi-ts

Version:

🌀 OpenAPI to TypeScript code generator. Generate API clients, SDKs, validators, and more.

212 lines (193 loc) • 5.92 kB
import { getAuthToken } from '../core/auth'; import type { QuerySerializerOptions } from '../core/bodySerializer'; import { serializeArrayParam, serializeObjectParam, serializePrimitiveParam, } from '../core/pathSerializer'; import { getUrl } from '../core/utils'; import type { Client, ClientOptions, Config, RequestOptions } from './types'; export const createQuerySerializer = <T = unknown>({ parameters = {}, ...args }: QuerySerializerOptions = {}) => { const querySerializer = (queryParams: T) => { const search: string[] = []; if (queryParams && typeof queryParams === 'object') { for (const name in queryParams) { const value = queryParams[name]; if (value === undefined || value === null) { continue; } const options = parameters[name] || args; if (Array.isArray(value)) { const serializedArray = serializeArrayParam({ allowReserved: options.allowReserved, explode: true, name, style: 'form', value, ...options.array, }); if (serializedArray) search.push(serializedArray); } else if (typeof value === 'object') { const serializedObject = serializeObjectParam({ allowReserved: options.allowReserved, explode: true, name, style: 'deepObject', value: value as Record<string, unknown>, ...options.object, }); if (serializedObject) search.push(serializedObject); } else { const serializedPrimitive = serializePrimitiveParam({ allowReserved: options.allowReserved, name, value: value as string, }); if (serializedPrimitive) search.push(serializedPrimitive); } } } return search.join('&'); }; return querySerializer; }; const checkForExistence = ( options: Pick<RequestOptions, 'auth' | 'query'> & { headers: Record<any, unknown>; }, name?: string, ): boolean => { if (!name) { return false; } if (name in options.headers || options.query?.[name]) { return true; } if ( 'Cookie' in options.headers && options.headers['Cookie'] && typeof options.headers['Cookie'] === 'string' ) { return options.headers['Cookie'].includes(`${name}=`); } return false; }; export const setAuthParams = async ({ security, ...options }: Pick<Required<RequestOptions>, 'security'> & Pick<RequestOptions, 'auth' | 'query'> & { headers: Record<any, unknown>; }) => { for (const auth of security) { if (checkForExistence(options, auth.name)) { continue; } const token = await getAuthToken(auth, options.auth); if (!token) { continue; } const name = auth.name ?? 'Authorization'; switch (auth.in) { case 'query': if (!options.query) { options.query = {}; } options.query[name] = token; break; case 'cookie': { const value = `${name}=${token}`; if ('Cookie' in options.headers && options.headers['Cookie']) { options.headers['Cookie'] = `${options.headers['Cookie']}; ${value}`; } else { options.headers['Cookie'] = value; } break; } case 'header': default: options.headers[name] = token; break; } } }; export const buildUrl: Client['buildUrl'] = (options) => { const instanceBaseUrl = options.axios?.defaults?.baseURL; const baseUrl = !!options.baseURL && typeof options.baseURL === 'string' ? options.baseURL : instanceBaseUrl; return getUrl({ baseUrl: baseUrl as string, path: options.path, // let `paramsSerializer()` handle query params if it exists query: !options.paramsSerializer ? options.query : undefined, querySerializer: typeof options.querySerializer === 'function' ? options.querySerializer : createQuerySerializer(options.querySerializer), url: options.url, }); }; export const mergeConfigs = (a: Config, b: Config): Config => { const config = { ...a, ...b }; config.headers = mergeHeaders(a.headers, b.headers); return config; }; /** * Special Axios headers keywords allowing to set headers by request method. */ export const axiosHeadersKeywords = [ 'common', 'delete', 'get', 'head', 'patch', 'post', 'put', ] as const; export const mergeHeaders = ( ...headers: Array<Required<Config>['headers'] | undefined> ): Record<any, unknown> => { const mergedHeaders: Record<any, unknown> = {}; for (const header of headers) { if (!header || typeof header !== 'object') { continue; } const iterator = Object.entries(header); for (const [key, value] of iterator) { if ( axiosHeadersKeywords.includes( key as (typeof axiosHeadersKeywords)[number], ) && typeof value === 'object' ) { mergedHeaders[key] = { ...(mergedHeaders[key] as Record<any, unknown>), ...value, }; } else if (value === null) { delete mergedHeaders[key]; } else if (Array.isArray(value)) { for (const v of value) { // @ts-expect-error mergedHeaders[key] = [...(mergedHeaders[key] ?? []), v as string]; } } else if (value !== undefined) { // assume object headers are meant to be JSON stringified, i.e. their // content value in OpenAPI specification is 'application/json' mergedHeaders[key] = typeof value === 'object' ? JSON.stringify(value) : (value as string); } } } return mergedHeaders; }; export const createConfig = <T extends ClientOptions = ClientOptions>( override: Config<Omit<ClientOptions, keyof T> & T> = {}, ): Config<Omit<ClientOptions, keyof T> & T> => ({ ...override, });