Improves API client response handling and idempotency

Extends `X-Idempotency-Key` header usage to `DELETE` and `PUT` requests, ensuring idempotent behavior for a wider range of modifying API operations. Updates the documentation and client implementation for `DELETE` requests.

Refactors `handleResponse` to robustly parse API responses. It now reads the response body once as text, enabling graceful handling of non-JSON error bodies and consistent processing of successful or empty responses.
This commit is contained in:
2026-03-24 19:08:22 +03:00
parent 28c24d8cb1
commit 02e8c2a89b
2 changed files with 18 additions and 8 deletions
+16 -6
View File
@@ -40,14 +40,24 @@ async function buildHeaders(
}
async function handleResponse<T>(response: Response): Promise<T> {
const rawBody = await response.text();
if (!response.ok) {
const error = await response.json().catch(() => ({}));
const msg = (error as { message?: string }).message ?? response.statusText;
let msg = response.statusText;
if (rawBody) {
try {
const error = JSON.parse(rawBody) as { message?: string };
msg = error.message ?? rawBody;
} catch {
msg = rawBody;
}
}
throw new Error(`API error [${response.status}]: ${msg}`);
}
// 204 No Content
if (response.status === 204) return {} as T;
return response.json() as Promise<T>;
if (!rawBody) return {} as T;
return JSON.parse(rawBody) as T;
}
export async function apiGet<T>(
@@ -98,7 +108,7 @@ export async function apiPatch<T>(
}
export async function apiDelete<T>(path: string): Promise<T> {
const headers = await buildHeaders("DELETE", path, "", false);
const headers = await buildHeaders("DELETE", path, "", true);
const response = await fetch(`${config.baseUrl}${path}`, {
method: "DELETE",