type ApiErrorPayload = { message?: string; issues?: { formErrors?: string[]; fieldErrors?: Record; }; }; type ApiLikeError = Error & { statusCode?: number; status?: number; data?: ApiErrorPayload; }; const apiFieldLabels: Record = { 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(path: string, options: Parameters>[1] = {}) { const config = useRuntimeConfig(); const token = useState("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(`${baseUrl}${path}`, { ...options, headers, credentials: "include" }).catch((error: ApiLikeError) => { throw new Error(getApiErrorMessage(error)); }); }