Files
eryao/web/src/lib/api-client.ts
T
2026-05-09 16:00:29 +08:00

52 lines
1.4 KiB
TypeScript

const apiBase = (): string => import.meta.env.PUBLIC_API_URL || '';
export function apiUrl(path: string): string {
return path.startsWith('http') ? path : `${apiBase()}${path}`;
}
export class ApiError extends Error {
status: number;
code?: string;
detail?: string;
constructor(status: number, title: string, code?: string, detail?: string) {
super(title);
this.name = 'ApiError';
this.status = status;
this.code = code;
this.detail = detail;
}
}
export async function toApiError(res: Response): Promise<ApiError> {
try {
const body = await res.json();
return new ApiError(
res.status,
body.title || body.detail || `Request failed (${res.status})`,
body.code,
body.detail,
);
} catch {
return new ApiError(res.status, `Request failed (${res.status})`);
}
}
export function jsonHeaders(options?: RequestInit): Headers {
const headers = new Headers(options?.headers);
if (!headers.has('Content-Type') && !(options?.body instanceof FormData)) {
headers.set('Content-Type', 'application/json');
}
return headers;
}
export async function apiRequest<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(apiUrl(path), {
...options,
headers: jsonHeaders(options),
});
if (!res.ok) throw await toApiError(res);
if (res.status === 204) return undefined as T;
return res.json() as Promise<T>;
}