74 lines
2.0 KiB
TypeScript
74 lines
2.0 KiB
TypeScript
type JsonErrorPayload = {
|
|
error?: string;
|
|
message?: string;
|
|
detail?: string;
|
|
};
|
|
|
|
const MAX_ERROR_TEXT = 240;
|
|
|
|
function summarizeResponseText(raw: string): string {
|
|
const compact = raw.replace(/\s+/g, " ").trim();
|
|
if (!compact) return "";
|
|
if (compact.length <= MAX_ERROR_TEXT) return compact;
|
|
return `${compact.slice(0, MAX_ERROR_TEXT - 3)}...`;
|
|
}
|
|
|
|
function defaultHttpMessage(response: Response): string {
|
|
const suffix = response.statusText?.trim() ? ` ${response.statusText.trim()}` : "";
|
|
return `HTTP ${response.status}${suffix}`;
|
|
}
|
|
|
|
function extractErrorMessage(
|
|
response: Response,
|
|
raw: string,
|
|
payload: JsonErrorPayload | null,
|
|
): string {
|
|
const candidate =
|
|
(typeof payload?.error === "string" && payload.error.trim()) ||
|
|
(typeof payload?.message === "string" && payload.message.trim()) ||
|
|
(typeof payload?.detail === "string" && payload.detail.trim()) ||
|
|
summarizeResponseText(raw);
|
|
return candidate || defaultHttpMessage(response);
|
|
}
|
|
|
|
export async function fetchJsonResponse<T>(url: string, init?: RequestInit): Promise<T> {
|
|
const response = await fetch(url, init);
|
|
const raw = await response.text();
|
|
const trimmed = raw.trim();
|
|
let payload: (T & JsonErrorPayload) | null = null;
|
|
|
|
if (trimmed) {
|
|
try {
|
|
payload = JSON.parse(trimmed) as T & JsonErrorPayload;
|
|
} catch {
|
|
if (!response.ok) {
|
|
throw new Error(extractErrorMessage(response, trimmed, null));
|
|
}
|
|
throw new Error(`Invalid JSON response from ${url}`);
|
|
}
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error(extractErrorMessage(response, trimmed, payload));
|
|
}
|
|
|
|
if (payload !== null) {
|
|
return payload as T;
|
|
}
|
|
|
|
return {} as T;
|
|
}
|
|
|
|
export async function readErrorMessage(response: Response): Promise<string> {
|
|
const raw = (await response.text()).trim();
|
|
let payload: JsonErrorPayload | null = null;
|
|
if (raw) {
|
|
try {
|
|
payload = JSON.parse(raw) as JsonErrorPayload;
|
|
} catch {
|
|
payload = null;
|
|
}
|
|
}
|
|
return extractErrorMessage(response, raw, payload);
|
|
}
|