/
aaronair
/
Test_task_rt_solution
Обзор
Документация
Войти
/
aaronair
/
Test_task_rt_solution
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/lib/api.ts
73 строки
2 KB
Ilikedrinkpivo
first_commit
28 май 2026, 14:51
28 май 2026, 14:51
b4498fc
Код
Авторство
О чём код?
/** Относительный /api/v1 по умолчанию — работает за одним ingress в production. */ const API_BASE = import.meta.env.VITE_API_BASE_URL || "/api/v1"; export class ApiError extends Error { constructor( message: string, public status: number, ) { super(message); this.name = "ApiError"; } } export function isApiEnabled(): boolean { return Boolean(API_BASE); } export async function apiFetch<T>( path: string, init?: RequestInit, ): Promise<T> { const url = `${API_BASE}${path}`; let res: Response; try { res = await fetch(url, { ...init, headers: { "Content-Type": "application/json", ...init?.headers, }, }); } catch (err) { const hint = API_BASE.includes("localhost") || API_BASE.includes("127.0.0.1") ? " (в бандле указан localhost — пересоберите frontend с VITE_API_BASE_URL=/api/v1)" : ""; throw new Error( `Не удалось связаться с API${hint}: ${err instanceof Error ? err.message : "Failed to fetch"}`, ); } if (!res.ok) { let message = res.statusText; try { const body = (await res.json()) as { error?: string }; if (body.error) message = body.error; } catch { /* ignore */ } throw new ApiError(message, res.status); } if (res.status === 204) return undefined as T; return res.json() as Promise<T>; } export async function apiUpload<T>( path: string, formData: FormData, query?: Record<string, string>, ): Promise<T> { const qs = query ? `?${new URLSearchParams(query)}` : ""; const url = `${API_BASE}${path}${qs}`; const res = await fetch(url, { method: "POST", body: formData }); if (!res.ok) { throw new ApiError(res.statusText, res.status); } return res.json() as Promise<T>; } export function apiEventsUrl(path: string): string { return `${API_BASE}${path}`; }