Files
your-gold/composables/useMyFetch.ts
2025-07-03 11:13:42 +02:00

75 lines
2.0 KiB
TypeScript

import { ofetch } from 'ofetch'
export interface RequestOptions<T> extends RequestInit {
onErrorOccured?: (error: Error, statusCode: number) => void
onSuccess?: (data: T, statusCode: number) => void
onStart?: () => void
}
/**
* @function useMyFetch
*
* @description
* Makes a request to a given url, handles cookies and errors.
*
* @param {string} url - The url to make a request to.
* @param {RequestOptions} [options] - The options to use for the request.
*
* @returns {Promise<T | undefined>} - A promise resolving to the response data
* or undefined if an error occurred.
*
* @example
* const { data } = useMyFetch<{ name: string }>('/api/user')
*/
export const useMyFetch = async <T>(
url: string,
options?: RequestOptions<T>,
): Promise<T> => {
if (options?.onStart) options.onStart()
let response = null
try {
const event = useRequestEvent()
if (options == null) options = {}
options.credentials = 'include'
if (import.meta.server) {
const api_uri
= event?.node.req.headers['api-uri'] || 'http://localhost:4000'
url = api_uri + url
options.headers = event?.headers
}
response = await ofetch.raw(url, options)
if (import.meta.server && !event?.handled) {
for (const cookie of response.headers.getSetCookie()) {
event?.headers.set('Cookie', cookie)
event?.node.res.setHeader('set-cookie', cookie)
}
}
// handle errors if any
if (!response.ok && typeof options.onErrorOccured == 'function') {
options.onErrorOccured(new Error(response.statusText), response.status)
}
// handle success to be able clearly marked that request has finished
if (response.ok && typeof options.onSuccess == 'function') {
options.onSuccess(response._data, response.status)
}
return response._data as T
}
catch (e) {
// handle errors if any
if (typeof options?.onErrorOccured == 'function') {
options.onErrorOccured(e as Error, response?.status || 500)
}
else {
console.error(e)
}
return {} as T
}
}