23 lines
1.1 KiB
TypeScript
23 lines
1.1 KiB
TypeScript
import { backendBaseUrl as BASE, joinBackendPath } from "./runtime-config";
|
|
|
|
export async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
|
|
// Only declare a JSON content-type when we actually send a body. Body-less
|
|
// POSTs (resume, close) would otherwise make Fastify reject the empty body
|
|
// with FST_ERR_CTP_EMPTY_JSON_BODY (400).
|
|
const headers: Record<string, string> = {
|
|
...(init?.headers as Record<string, string> | undefined),
|
|
};
|
|
if (init?.body != null && !("content-type" in headers) && !("Content-Type" in headers)) {
|
|
headers["content-type"] = "application/json";
|
|
}
|
|
const res = await fetch(joinBackendPath(BASE, path), { ...init, headers });
|
|
if (!res.ok) throw new Error(`${res.status} ${await res.text().catch(() => "")}`);
|
|
if (res.status === 204) return undefined as T;
|
|
// Accepted fire-and-forget endpoints may legitimately return 202 with no
|
|
// representation. Keep apiFetch useful for both 202 and 204 contracts.
|
|
const body = await res.text();
|
|
return body ? (JSON.parse(body) as T) : (undefined as T);
|
|
}
|
|
|
|
export { BASE };
|