feat(useApi): better interface

This commit is contained in:
2025-11-19 22:03:35 +01:00
parent 355653e4f2
commit 0b65e17903
11 changed files with 1080 additions and 106 deletions

View File

@@ -1,32 +1,67 @@
import type { FetchOptions } from 'ofetch';
import type { FetchError, FetchOptions } from 'ofetch';
import type { ApiError } from '~/types/api/error';
import type { HttpMethod } from '~/types/http-method';
import { QueryResult } from '~/types/query-result';
export const useApi = () => {
const config = useRuntimeConfig();
const apiFetch = $fetch.create({
baseURL: config.public.apiBase,
});
export interface UseApi {
get: <T>(path: string, opts?: FetchOptions, immediate?: boolean) => UseApiResponse<T>;
del: <T>(path: string, opts?: FetchOptions, immediate?: boolean) => UseApiResponse<T>;
post: <T, B = unknown>(path: string, opts?: FetchOptions, immediate?: boolean, body?: B) => UseApiResponse<T, B>;
put: <T, B = unknown>(path: string, opts?: FetchOptions, immediate?: boolean, body?: B) => UseApiResponse<T, B>;
patch: <T, B = unknown>(path: string, opts?: FetchOptions, immediate?: boolean, body?: B) => UseApiResponse<T, B>;
}
const get = <T>(url: string, options?: FetchOptions) => apiFetch<T>(url, { method: 'GET', ...options });
const createRequest = <ResponseT = unknown, PayloadT = unknown>(
method: HttpMethod,
url: string,
opts?: FetchOptions,
immediate: boolean = true,
body?: PayloadT,
): QueryResult<ResponseT, PayloadT> => {
const response = new QueryResult<ResponseT, PayloadT>();
const { apiBase } = useRuntimeConfig().public;
const post = <ResultT, PayloadT = Record<string, string | number | boolean>>(
url: string,
body?: PayloadT,
options?: FetchOptions,
) => apiFetch<ResultT>(url, { method: 'POST', body, ...options });
const run = async (requestBody?: PayloadT): Promise<void> => {
response.loading.value = true;
response.error.value = null;
const put = <ResultT, PayloadT = Record<string, string | number | boolean>>(
url: string,
body?: PayloadT,
options?: FetchOptions,
) => apiFetch<ResultT>(url, { method: 'PUT', body, ...options });
try {
const res = await $fetch<ResponseT>(url, {
baseURL: apiBase,
...opts,
method,
body: requestBody ?? undefined,
});
response.data.value = res;
} catch (e) {
const fetchError = e as FetchError;
const errBody = fetchError?.response?._data as ApiError | undefined;
response.error.value = errBody ?? {
message: fetchError.message || 'backend.errors.unknown',
success: false,
};
} finally {
response.loading.value = false;
}
};
response.run = run;
const patch = <ResultT, PayloadT = Record<string, string | number | boolean>>(
url: string,
body?: PayloadT,
options?: FetchOptions,
) => apiFetch<ResultT>(url, { method: 'PATCH', body, ...options });
if (immediate) run(body);
const del = <T>(url: string, options?: FetchOptions) => apiFetch<T>(url, { method: 'DELETE', ...options });
return response;
};
export const useApi = (): UseApi => {
const get = <T>(path: string, opts?: FetchOptions, immediate: boolean = true) =>
createRequest<T>('GET', path, opts, immediate);
const del = <T>(path: string, opts?: FetchOptions, immediate: boolean = true) =>
createRequest<T>('DELETE', path, opts, immediate);
const post = <T, B = unknown>(path: string, opts?: FetchOptions, immediate: boolean = true, body?: B) =>
createRequest<T, B>('POST', path, opts, immediate, body);
const put = <T, B = unknown>(path: string, opts?: FetchOptions, immediate: boolean = true, body?: B) =>
createRequest<T, B>('PUT', path, opts, immediate, body);
const patch = <T, B = unknown>(path: string, opts?: FetchOptions, immediate: boolean = true, body?: B) =>
createRequest<T, B>('PATCH', path, opts, immediate, body);
return { get, post, put, patch, del };
};