@hey-api/openapi-ts
Version:
🚀 The OpenAPI to TypeScript codegen. Generate clients, SDKs, validators, and more.
146 lines (126 loc) • 4.16 kB
text/typescript
import {
useAsyncData,
useFetch,
useLazyAsyncData,
useLazyFetch,
} from 'nuxt/app';
import { reactive, ref, watch } from 'vue';
import type { Client, Config } from './types';
import {
buildUrl,
createConfig,
executeFetchFn,
mergeConfigs,
mergeHeaders,
mergeInterceptors,
serializeBody,
setAuthParams,
} 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 request: Client['request'] = ({
asyncDataOptions,
composable,
...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 { responseTransformer, responseValidator, security } = opts;
if (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 }) => {
await setAuthParams({
auth: opts.auth,
headers: options.headers,
query: options.query,
security,
});
},
...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(opts, fetchFn);
}
if (composable === 'useFetch' || composable === 'useLazyFetch') {
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(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;
};
return {
buildUrl,
connect: (options) => request({ ...options, method: 'CONNECT' }),
delete: (options) => request({ ...options, method: 'DELETE' }),
get: (options) => request({ ...options, method: 'GET' }),
getConfig,
head: (options) => request({ ...options, method: 'HEAD' }),
options: (options) => request({ ...options, method: 'OPTIONS' }),
patch: (options) => request({ ...options, method: 'PATCH' }),
post: (options) => request({ ...options, method: 'POST' }),
put: (options) => request({ ...options, method: 'PUT' }),
request,
setConfig,
trace: (options) => request({ ...options, method: 'TRACE' }),
};
};