68 lines
2.1 KiB
TypeScript
68 lines
2.1 KiB
TypeScript
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? "";
|
|
|
|
export function apiUrl(path: string): string {
|
|
return `${API_BASE_URL}${path}`;
|
|
}
|
|
|
|
export class ApiHttpError extends Error {
|
|
readonly code: string;
|
|
readonly details?: unknown;
|
|
|
|
constructor(message: string, code = "REQUEST_ERROR", details?: unknown) {
|
|
super(message);
|
|
this.name = "ApiHttpError";
|
|
this.code = code;
|
|
this.details = details;
|
|
}
|
|
}
|
|
|
|
async function parseResponse<T>(response: Response): Promise<T> {
|
|
const payload = await response.json().catch(() => ({}));
|
|
if (!response.ok) {
|
|
const legacyError = typeof payload?.error === "object" && payload?.error !== null ? payload.error : null;
|
|
const code = typeof payload?.error === "string" ? payload.error : legacyError?.code ?? "REQUEST_ERROR";
|
|
const message = payload?.message ?? legacyError?.message ?? `Request failed (${response.status})`;
|
|
const details = payload?.details ?? legacyError?.details;
|
|
throw new ApiHttpError(message, code, details);
|
|
}
|
|
return payload.data as T;
|
|
}
|
|
|
|
export async function apiGet<T>(path: string): Promise<T> {
|
|
const response = await fetch(apiUrl(path));
|
|
return parseResponse<T>(response);
|
|
}
|
|
|
|
export async function apiPost<T>(path: string, body?: object): Promise<T> {
|
|
const response = await fetch(apiUrl(path), {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
return parseResponse<T>(response);
|
|
}
|
|
|
|
export async function apiPatch<T>(path: string, body?: object): Promise<T> {
|
|
const response = await fetch(apiUrl(path), {
|
|
method: "PATCH",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
return parseResponse<T>(response);
|
|
}
|
|
|
|
export async function apiDelete<T>(path: string): Promise<T> {
|
|
const response = await fetch(apiUrl(path), {
|
|
method: "DELETE",
|
|
});
|
|
return parseResponse<T>(response);
|
|
}
|
|
|
|
export async function apiMultipart<T>(path: string, form: FormData): Promise<T> {
|
|
const response = await fetch(apiUrl(path), {
|
|
method: "POST",
|
|
body: form,
|
|
});
|
|
return parseResponse<T>(response);
|
|
}
|