Files
badoHair_fe/lib/api.ts
2026-05-12 00:28:37 +00:00

97 lines
3.4 KiB
TypeScript

const BASE = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8000";
const PREFIX = "/api/v1";
if (typeof window !== "undefined") {
console.log("[API] base URL:", `${BASE}${PREFIX}`);
}
// ── Token management ──────────────────────────────────────────────────────────
export function getToken(): string | null {
if (typeof window === "undefined") return null;
return localStorage.getItem("bado_token");
}
export function setTokens(access: string, refresh: string) {
localStorage.setItem("bado_token", access);
localStorage.setItem("bado_refresh", refresh);
}
export function clearTokens() {
localStorage.removeItem("bado_token");
localStorage.removeItem("bado_refresh");
}
// ── Error ─────────────────────────────────────────────────────────────────────
export class ApiError extends Error {
code: string;
status: number;
details?: unknown;
constructor(code: string, message: string, status: number, details?: unknown) {
super(message);
this.code = code;
this.status = status;
this.details = details;
}
}
// ── Paginated result shape ────────────────────────────────────────────────────
export interface PaginatedResult<T> {
data: T[];
meta: { total: number; page: number; per_page: number; pages: number };
}
// ── Core request ──────────────────────────────────────────────────────────────
async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
const token = getToken();
const method = (init.method ?? "GET").toUpperCase();
const headers: Record<string, string> = {
...(init.headers as Record<string, string>),
};
if (method !== "GET" && method !== "DELETE" && !(init.body instanceof FormData)) {
headers["Content-Type"] = "application/json";
}
if (token) headers["Authorization"] = `Bearer ${token}`;
const res = await fetch(`${BASE}${PREFIX}${path}`, { ...init, headers });
if (res.status === 204) return undefined as unknown as T;
const body = await res.json();
if (body.success === false) {
const err = body.error ?? {};
throw new ApiError(
err.code ?? "UNKNOWN",
err.message ?? "Une erreur est survenue",
res.status,
err.details
);
}
if ("meta" in body) {
return { data: body.data, meta: body.meta } as T;
}
return body.data as T;
}
export const api = {
get: <T>(path: string) => request<T>(path),
post: <T>(path: string, data?: unknown) =>
request<T>(path, {
method: "POST",
body: data !== undefined ? JSON.stringify(data) : undefined,
}),
put: <T>(path: string, data?: unknown) =>
request<T>(path, { method: "PUT", body: JSON.stringify(data) }),
patch: <T>(path: string, data?: unknown) =>
request<T>(path, { method: "PATCH", body: JSON.stringify(data) }),
del: <T = void>(path: string) => request<T>(path, { method: "DELETE" }),
upload: <T>(path: string, formData: FormData) =>
request<T>(path, { method: "POST", body: formData }),
};