UNPKG

@hey-api/openapi-ts

Version:

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

228 lines (200 loc) • 6 kB
import { useAsyncData, useFetch, useLazyAsyncData, useLazyFetch, } from 'nuxt/app'; import { reactive, ref, watch } from 'vue'; import { createSseClient } from '../core/serverSentEvents'; import type { HttpMethod } from '../core/types'; import type { Client, Config, RequestOptions } from './types'; import { buildUrl, createConfig, executeFetchFn, mergeConfigs, mergeHeaders, mergeInterceptors, serializeBody, setAuthParams, unwrapRefs, } from './utils'; export const createClient = (config: Config = {}): Client => { let _config = mergeConfigs(createConfig(), config); const getConfig = (): Config => ({ ..._config }); const setConfig = (config: Config): Config => { _config = mergeConfigs(_config, config); return getConfig(); }; const beforeRequest = async (options: RequestOptions) => { const opts = { ..._config, ...options, $fetch: options.$fetch ?? _config.$fetch ?? $fetch, headers: mergeHeaders(_config.headers, options.headers), onRequest: mergeInterceptors(_config.onRequest, options.onRequest), onResponse: mergeInterceptors(_config.onResponse, options.onResponse), }; if (opts.security) { await setAuthParams({ ...opts, security: opts.security, }); } if (opts.requestValidator) { await opts.requestValidator(opts); } const url = buildUrl(opts); return { opts, url }; }; const request: Client['request'] = ({ asyncDataOptions, composable = '$fetch', ...options }) => { const key = options.key; const opts = { ..._config, ...options, $fetch: options.$fetch ?? _config.$fetch ?? $fetch, headers: mergeHeaders(_config.headers, options.headers), onRequest: mergeInterceptors(_config.onRequest, options.onRequest), onResponse: mergeInterceptors(_config.onResponse, options.onResponse), }; const { requestValidator, responseTransformer, responseValidator, security, } = opts; if (requestValidator || security) { // auth must happen in interceptors otherwise we'd need to require // asyncContext enabled // https://nuxt.com/docs/guide/going-further/experimental-features#asynccontext opts.onRequest = [ async ({ options }) => { if (security) { await setAuthParams({ auth: opts.auth, headers: options.headers, query: options.query, security, }); } if (requestValidator) { await requestValidator({ ...options, // @ts-expect-error body: options.rawBody, }); } }, ...opts.onRequest, ]; } if (responseTransformer || responseValidator) { opts.onResponse = [ ...opts.onResponse, async ({ options, response }) => { if (options.responseType && options.responseType !== 'json') { return; } if (!response.ok) { return; } if (responseValidator) { await responseValidator(response._data); } if (responseTransformer) { response._data = await responseTransformer(response._data); } }, ]; } // remove Content-Type header if body is empty to avoid sending invalid requests if (opts.body === undefined || opts.body === '') { opts.headers.delete('Content-Type'); } const fetchFn = opts.$fetch; if (composable === '$fetch') { return executeFetchFn( // @ts-expect-error opts, fetchFn, ); } if (composable === 'useFetch' || composable === 'useLazyFetch') { opts.rawBody = opts.body; const bodyParams = reactive({ body: opts.body, bodySerializer: opts.bodySerializer, }); const body = ref(serializeBody(opts)); opts.body = body; watch(bodyParams, (changed) => { body.value = serializeBody(changed); }); return composable === 'useLazyFetch' ? useLazyFetch(() => buildUrl(opts), opts) : useFetch(() => buildUrl(opts), opts); } const handler: any = () => executeFetchFn( // @ts-expect-error opts, fetchFn, ); if (composable === 'useAsyncData') { return key ? useAsyncData(key, handler, asyncDataOptions) : useAsyncData(handler, asyncDataOptions); } if (composable === 'useLazyAsyncData') { return key ? useLazyAsyncData(key, handler, asyncDataOptions) : useLazyAsyncData(handler, asyncDataOptions); } return undefined as any; }; const makeMethodFn = (method: Uppercase<HttpMethod>) => (options: RequestOptions) => request({ ...options, method }); const makeSseFn = (method: Uppercase<HttpMethod>) => async (options: RequestOptions) => { const { opts, url } = await beforeRequest(options); return createSseClient({ ...unwrapRefs(opts), body: opts.body as BodyInit | null | undefined, method, onRequest: undefined, signal: unwrapRefs(opts.signal) as AbortSignal, url, }); }; return { buildUrl, connect: makeMethodFn('CONNECT'), delete: makeMethodFn('DELETE'), get: makeMethodFn('GET'), getConfig, head: makeMethodFn('HEAD'), options: makeMethodFn('OPTIONS'), patch: makeMethodFn('PATCH'), post: makeMethodFn('POST'), put: makeMethodFn('PUT'), request, setConfig, sse: { connect: makeSseFn('CONNECT'), delete: makeSseFn('DELETE'), get: makeSseFn('GET'), head: makeSseFn('HEAD'), options: makeSseFn('OPTIONS'), patch: makeSseFn('PATCH'), post: makeSseFn('POST'), put: makeSseFn('PUT'), trace: makeSseFn('TRACE'), }, trace: makeMethodFn('TRACE'), } as Client; };