Skip to content

Instantly share code, notes, and snippets.

@BarishNamazov
Last active March 28, 2024 00:46
Show Gist options
  • Select an option

  • Save BarishNamazov/f9827165c4259d29b16a99c9d018588c to your computer and use it in GitHub Desktop.

Select an option

Save BarishNamazov/f9827165c4259d29b16a99c9d018588c to your computer and use it in GitHub Desktop.
Custom wrapper for Nuxt's useFetch while keeping type completion features
import type { AsyncData, UseFetchOptions, FetchResult } from "nuxt/app";
import type { FetchError } from "ofetch";
import type {
NitroFetchRequest,
AvailableRouterMethod as _AvailableRouterMethod,
} from "nitropack";
// Custom options
interface UseFetchyOptions<
_ResT,
DataT,
PickKeys extends KeysOf<DataT>,
DefaultT,
ReqT extends NitroFetchRequest,
Method extends AvailableRouterMethod<ReqT>
> extends UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method> {
alert?: boolean;
suppress?: boolean;
}
type PickFrom<T, K extends Array<string>> = T extends Array<any>
? T
: T extends Record<string, any>
? keyof T extends K[number]
? T
: K[number] extends never
? T
: Pick<T, K[number]>
: T;
type KeysOf<T> = Array<
T extends T ? (keyof T extends string ? keyof T : never) : never
>;
type AvailableRouterMethod<R extends NitroFetchRequest> =
| _AvailableRouterMethod<R>
| Uppercase<_AvailableRouterMethod<R>>;
// My custom fetch wrapper enables toasts
// You probably don't want this import
import toasteventbus from "primevue/toasteventbus";
// Note use of UseFetchyOptions (custom interface defined above)
// for opts parameter
export async function useFetchy<
ResT = void,
ErrorT = FetchError,
ReqT extends NitroFetchRequest = NitroFetchRequest,
Method extends AvailableRouterMethod<ReqT> = ResT extends void
? "get" extends AvailableRouterMethod<ReqT>
? "get"
: AvailableRouterMethod<ReqT>
: AvailableRouterMethod<ReqT>,
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
DataT = _ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = DataT
>(
request: Ref<ReqT> | ReqT | (() => ReqT),
opts: UseFetchyOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method> = {}
): Promise<AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | null>> {
// Custom logic inside
opts.alert = opts.alert ?? true;
opts.suppress = opts.suppress ?? true;
let successMessage = "";
let errorMessage = "";
// Actual call to original useFetch
const result = await useFetch<
ResT,
ErrorT,
ReqT,
Method,
_ResT,
DataT,
PickKeys,
DefaultT
>(request, {
...opts,
onResponse({ response }) {
if (response.ok) {
successMessage = response._data?.message;
} else {
errorMessage = response._data?.message || response.statusText;
}
},
});
if (opts.alert && errorMessage) {
toasteventbus.emit("add", {
severity: "error",
summary: "Something went wrong",
detail: errorMessage,
life: 5000,
});
}
if (opts.alert && successMessage) {
toasteventbus.emit("add", {
severity: "success",
summary: "Success",
detail: successMessage,
life: 2000,
});
}
if (!opts.suppress && result.error.value) {
throw result.error.value;
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment