14 lines
1.3 KiB
TypeScript
14 lines
1.3 KiB
TypeScript
|
|
'use client';
|
||
|
|
export class ApiError extends Error { constructor(public status: number, public code: string, message: string, public details?: { path: string; message: string }[]) { super(message); } }
|
||
|
|
let csrf = '';
|
||
|
|
export const setCsrf = (t: string) => { csrf = t; };
|
||
|
|
|
||
|
|
/** Einheitlicher API-Zugriff über den same-origin Proxy /api (Cookie, CSRF-Header, normalisierte Fehler). */
|
||
|
|
export async function api<T = unknown>(method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', path: string, body?: unknown): Promise<T> {
|
||
|
|
const res = await fetch(`/api${path}`, { method, credentials: 'same-origin', headers: { ...(body !== undefined ? { 'content-type': 'application/json' } : {}), ...(csrf ? { 'x-csrf-token': csrf } : {}) }, body: body !== undefined ? JSON.stringify(body) : undefined });
|
||
|
|
const data = res.headers.get('content-type')?.includes('json') ? await res.json() : null;
|
||
|
|
if (!res.ok) throw new ApiError(res.status, data?.error?.code ?? 'ERROR', data?.error?.message ?? 'Anfrage fehlgeschlagen', data?.error?.details);
|
||
|
|
return data as T;
|
||
|
|
}
|
||
|
|
export const errMsg = (e: unknown): string => e instanceof ApiError ? (e.details?.length ? `${e.message}: ${e.details.map((d) => d.message).join(', ')}` : e.message) : 'Der Server ist nicht erreichbar. Bitte später erneut versuchen.';
|