client: tolerate empty response bodies on 2xx
Every verb ended in an unconditional res.json(), which throws "Unexpected end of JSON input" on 201/204 responses that carry no body — so a request that actually succeeded still surfaced as an error (e.g. a sent chat message toasting a failure). Read text first and only parse when non-empty, otherwise resolve undefined. Non-empty JSON is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,13 @@ export const getHeaders = (isText: boolean = false) => {
|
||||
return headers;
|
||||
};
|
||||
|
||||
// 2xx responses can legitimately carry no body (201 Created / 204 No Content). res.json() throws on an
|
||||
// empty body, so read text first and only parse when there's something — otherwise resolve undefined.
|
||||
const parseBody = async <T>(res: Response): Promise<T> => {
|
||||
const text = await res.text();
|
||||
return (text ? JSON.parse(text) : undefined) as T;
|
||||
};
|
||||
|
||||
export const getText = async (uri: string, baseUrl = '') => {
|
||||
const headers = getHeaders(true);
|
||||
const theUrl = baseUrl ? `${baseUrl}/${uri.replace(/^\//, '')}` : uri;
|
||||
@@ -67,8 +74,7 @@ export const get = async <T>(uri: string, baseUrl = '') => {
|
||||
const theUrl = baseUrl ? `${baseUrl}/${uri.replace(/^\//, '')}` : uri;
|
||||
const res = await fetch(theUrl, { headers });
|
||||
await validateResponse(res);
|
||||
const data = await res.json();
|
||||
return data as T;
|
||||
return parseBody<T>(res);
|
||||
};
|
||||
|
||||
export const getBlob = async (uri: string, baseUrl = '') => {
|
||||
@@ -100,8 +106,7 @@ export const post = async <T>(uri: string, payload?: any, baseUrl = '') => {
|
||||
headers,
|
||||
});
|
||||
await validateResponse(res);
|
||||
const data = await res.json();
|
||||
return data as T;
|
||||
return parseBody<T>(res);
|
||||
};
|
||||
|
||||
export const put = async <T>(uri: string, payload?: any, baseUrl = '') => {
|
||||
@@ -119,8 +124,7 @@ export const put = async <T>(uri: string, payload?: any, baseUrl = '') => {
|
||||
headers,
|
||||
});
|
||||
await validateResponse(res);
|
||||
const data = await res.json();
|
||||
return data as T;
|
||||
return parseBody<T>(res);
|
||||
};
|
||||
|
||||
export const patch = async <T>(uri: string, payload?: any, baseUrl = '') => {
|
||||
@@ -132,8 +136,7 @@ export const patch = async <T>(uri: string, payload?: any, baseUrl = '') => {
|
||||
headers,
|
||||
});
|
||||
await validateResponse(res);
|
||||
const data = await res.json();
|
||||
return data as T;
|
||||
return parseBody<T>(res);
|
||||
};
|
||||
|
||||
export const DELETE = async <T>(uri: string, payload?: any, baseUrl = '') => {
|
||||
@@ -145,8 +148,7 @@ export const DELETE = async <T>(uri: string, payload?: any, baseUrl = '') => {
|
||||
headers,
|
||||
});
|
||||
await validateResponse(res);
|
||||
const data = await res.json();
|
||||
return data as T;
|
||||
return parseBody<T>(res);
|
||||
};
|
||||
|
||||
const validateResponse = async (res: Response) => {
|
||||
|
||||
Reference in New Issue
Block a user