Skip to content

Commit 497e960

Browse files
author
jbarba
committed
fix(openapi-fetch): avoid errors parsing empty JSON bodies (200 with no content)
1 parent 12f9c29 commit 497e960

File tree

6 files changed

+86
-6
lines changed

6 files changed

+86
-6
lines changed

.changeset/wet-waves-turn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"openapi-fetch": patch
3+
---
4+
5+
Use text() when no content-length is provided to avoid errors parsing empty bodies (200 with no content)

packages/openapi-fetch/src/index.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,18 +230,27 @@ export default function createClient(clientOptions) {
230230
}
231231
}
232232

233+
const contentLength = response.headers.get("Content-Length");
233234
// handle empty content
234-
if (response.status === 204 || request.method === "HEAD" || response.headers.get("Content-Length") === "0") {
235+
if (response.status === 204 || request.method === "HEAD" || contentLength === "0") {
235236
return response.ok ? { data: undefined, response } : { error: undefined, response };
236237
}
237238

238239
// parse response (falling back to .text() when necessary)
239240
if (response.ok) {
240-
// if "stream", skip parsing entirely
241-
if (parseAs === "stream") {
242-
return { data: response.body, response };
243-
}
244-
return { data: await response[parseAs](), response };
241+
const parseData = async () => {
242+
// if "stream", skip parsing entirely
243+
if (parseAs === "stream") return response.body;
244+
245+
if (parseAs === "json" && !contentLength) {
246+
// use text() when no content-length is provided to avoid errors parsing empty bodies (200 with no content)
247+
const raw = await response.text();
248+
return raw ? JSON.parse(raw) : undefined;
249+
}
250+
251+
return await response[parseAs]();
252+
};
253+
return { data: await parseData(), response };
245254
}
246255

247256
// handle errors

packages/openapi-fetch/test/common/request.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ describe("request", () => {
342342
clone: () => ({ ...response }),
343343
headers: new Headers(),
344344
json: async () => data,
345+
text: async () => JSON.stringify(data),
345346
status: 200,
346347
ok: true,
347348
} as Response;

packages/openapi-fetch/test/common/response.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,18 @@ describe("response", () => {
138138
describe("parseAs", () => {
139139
const client = createObservedClient<paths>({}, async () => Response.json({}));
140140

141+
test("json with empty response", async () => {
142+
const client = createObservedClient<paths>({}, async () => new Response());
143+
const { data, error } = (await client.GET("/empty-json", {
144+
parseAs: "json",
145+
})) satisfies { data?: undefined };
146+
if (error) {
147+
throw new Error("parseAs json: error");
148+
}
149+
150+
expect(data).toBe(undefined);
151+
});
152+
141153
test("text", async () => {
142154
const { data, error } = (await client.GET("/resources", {
143155
parseAs: "text",

packages/openapi-fetch/test/common/schemas/common.d.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,22 @@ export interface paths {
727727
patch?: never;
728728
trace?: never;
729729
};
730+
"/empty-json": {
731+
parameters: {
732+
query?: never;
733+
header?: never;
734+
path?: never;
735+
cookie?: never;
736+
};
737+
get: operations["getEmptyJsonResponse"];
738+
put?: never;
739+
post?: never;
740+
delete?: never;
741+
options?: never;
742+
head?: never;
743+
patch?: never;
744+
trace?: never;
745+
};
730746
}
731747
export type webhooks = Record<string, never>;
732748
export interface components {
@@ -779,4 +795,30 @@ export interface operations {
779795
};
780796
};
781797
};
798+
getEmptyJsonResponse: {
799+
parameters: {
800+
query?: never;
801+
header?: never;
802+
path?: never;
803+
cookie?: never;
804+
};
805+
requestBody?: never;
806+
responses: {
807+
/** @description Empty JSON Response */
808+
200: {
809+
headers: {
810+
[name: string]: unknown;
811+
};
812+
content?: never;
813+
};
814+
default: {
815+
headers: {
816+
[name: string]: unknown;
817+
};
818+
content: {
819+
"application/json": components["schemas"]["Error"];
820+
};
821+
};
822+
};
823+
};
782824
}

packages/openapi-fetch/test/common/schemas/common.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,17 @@ paths:
421421
application/json:
422422
schema:
423423
$ref: "#/components/schemas/Error"
424+
/empty-json:
425+
get:
426+
operationId: getEmptyJsonResponse
427+
responses:
428+
200:
429+
description: Empty JSON Response
430+
default:
431+
content:
432+
application/json:
433+
schema:
434+
$ref: "#/components/schemas/Error"
424435
components:
425436
schemas:
426437
Error:

0 commit comments

Comments
 (0)