Files
antigol-service/frontend/composables/useApi.ts
talorr cda36918e8 init
2026-03-27 03:36:08 +03:00

92 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
type ApiErrorPayload = {
message?: string;
issues?: {
formErrors?: string[];
fieldErrors?: Record<string, string[] | undefined>;
};
};
type ApiLikeError = Error & {
statusCode?: number;
status?: number;
data?: ApiErrorPayload;
};
const apiFieldLabels: Record<string, string> = {
email: "Email",
password: "Пароль",
confirmPassword: "Повтор пароля",
title: "Заголовок",
body: "Текст",
status: "Статус",
startsAt: "Начало",
expiresAt: "Окончание"
};
function getApiFieldLabel(field: string) {
return apiFieldLabels[field] ?? field;
}
function getApiErrorMessage(error: ApiLikeError) {
const formErrors = Array.isArray(error.data?.issues?.formErrors)
? error.data!.issues!.formErrors.filter((entry) => typeof entry === "string" && entry.trim())
: [];
if (formErrors.length > 0) {
return formErrors.join("\n");
}
const fieldErrors = error.data?.issues?.fieldErrors;
if (fieldErrors && typeof fieldErrors === "object") {
const messages = Object.entries(fieldErrors)
.flatMap(([field, value]) =>
(Array.isArray(value) ? value : [])
.filter((entry) => typeof entry === "string" && entry.trim())
.map((entry) => `${getApiFieldLabel(field)}: ${entry}`)
);
if (messages.length > 0) {
return messages.join("\n");
}
}
const responseMessage = typeof error.data?.message === "string" ? error.data.message.trim() : "";
if (responseMessage) {
return responseMessage;
}
const statusCode = error.statusCode ?? error.status;
if (statusCode === 400) return "Проверьте правильность заполнения формы";
if (statusCode === 401) return "Неверный логин или пароль";
if (statusCode === 403) return "Недостаточно прав для выполнения действия";
if (statusCode === 404) return "Запрашиваемые данные не найдены";
if (statusCode === 409) return "Такая запись уже существует";
if (statusCode === 422) return "Не удалось обработать введённые данные";
if (statusCode && statusCode >= 500) return "Ошибка сервера. Попробуйте ещё раз позже";
return error.message || "Не удалось выполнить запрос";
}
export function useApi<T>(path: string, options: Parameters<typeof $fetch<T>>[1] = {}) {
const config = useRuntimeConfig();
const token = useState<string | null>("auth-token", () => null);
const baseUrl = process.server ? config.apiBaseInternal : config.public.apiBase;
const headers = new Headers(options.headers as HeadersInit | undefined);
if (!headers.has("Content-Type") && options.method && options.method !== "GET") {
headers.set("Content-Type", "application/json");
}
if (token.value) {
headers.set("Authorization", `Bearer ${token.value}`);
}
return $fetch<T>(`${baseUrl}${path}`, {
...options,
headers,
credentials: "include"
}).catch((error: ApiLikeError) => {
throw new Error(getApiErrorMessage(error));
});
}