27 lines
857 B
TypeScript
27 lines
857 B
TypeScript
/* Browser-side fetch helper for the JSON API. */
|
|
|
|
export class ApiError extends Error {
|
|
constructor(
|
|
public status: number,
|
|
message: string,
|
|
public details?: unknown
|
|
) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
export async function api<T = unknown>(url: string, init?: RequestInit & { json?: unknown }): Promise<T> {
|
|
const { json, ...rest } = init ?? {};
|
|
const res = await fetch(url, {
|
|
...rest,
|
|
headers: json !== undefined ? { "content-type": "application/json", ...rest.headers } : rest.headers,
|
|
body: json !== undefined ? JSON.stringify(json) : rest.body,
|
|
});
|
|
const data = await res.json().catch(() => ({}));
|
|
if (!res.ok) {
|
|
const details = Array.isArray(data.details) ? `: ${data.details.join("; ")}` : "";
|
|
throw new ApiError(res.status, (data.error ?? res.statusText) + details, data.details);
|
|
}
|
|
return data as T;
|
|
}
|