Skip to content

Commit 80717a7

Browse files
authored
Fix 2XX, 4XX, 5XX responses (#1251)
* Fix 2XX, 4XX, 5XX responses * Add 2XX, 4XX, 5XX test
1 parent a33775b commit 80717a7

File tree

6 files changed

+147
-2
lines changed

6 files changed

+147
-2
lines changed

.changeset/stale-shoes-sell.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"openapi-fetch": patch
3+
---
4+
5+
Fix 2XX, 4XX, 5XX responses

packages/openapi-fetch/src/index.test.ts

+15
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,21 @@ describe("client", () => {
516516
// assert array type (and only array type) was inferred
517517
expect(data.length).toBe(0);
518518
});
519+
520+
it("handles literal 2XX and 4XX codes", async () => {
521+
const client = createClient<paths>();
522+
mockFetch({ status: 201, body: '{"status": "success"}' });
523+
const { data, error } = await client.PUT("/media", { body: { media: "base64", name: "myImage" } });
524+
525+
if (data) {
526+
// assert 2XX type inferred correctly
527+
expect(data.status).toBe("success");
528+
} else {
529+
// assert 4XX type inferred correctly
530+
// (this should be a dead code path but tests TS types)
531+
expect(error.message).toBe("Error");
532+
}
533+
});
519534
});
520535

521536
describe("POST()", () => {

packages/openapi-fetch/src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ export interface OperationObject {
2929
responses: any;
3030
}
3131
export type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace";
32-
export type OkStatus = 200 | 201 | 202 | 203 | 204 | 206 | 207;
32+
export type OkStatus = 200 | 201 | 202 | 203 | 204 | 206 | 207 | "2XX";
3333
// prettier-ignore
34-
export type ErrorStatus = 500 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 429 | 431 | 444 | 450 | 451 | 497 | 498 | 499 | "default";
34+
export type ErrorStatus = 500 | '5XX' | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 429 | 431 | 444 | 450 | 451 | 497 | 498 | 499 | '4XX' | "default";
3535

3636
// util
3737
/** Get a union of paths which have method */

packages/openapi-fetch/test/v1.d.ts

+23
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,29 @@ export interface paths {
112112
"/header-params": {
113113
get: operations["getHeaderParams"];
114114
};
115+
"/media": {
116+
put: {
117+
requestBody: {
118+
content: {
119+
"application/json": {
120+
/** Format: blob */
121+
media: string;
122+
name: string;
123+
};
124+
};
125+
};
126+
responses: {
127+
"2XX": {
128+
content: {
129+
"application/json": {
130+
status: string;
131+
};
132+
};
133+
};
134+
"4XX": components["responses"]["Error"];
135+
};
136+
};
137+
};
115138
"/self": {
116139
get: {
117140
responses: {

packages/openapi-fetch/test/v1.yaml

+30
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,36 @@ paths:
123123
- status
124124
500:
125125
$ref: '#/components/responses/Error'
126+
/media:
127+
put:
128+
requestBody:
129+
required: true
130+
content:
131+
application/json:
132+
schema:
133+
type: object
134+
properties:
135+
media:
136+
type: string
137+
format: blob
138+
name:
139+
type: string
140+
required:
141+
- media
142+
- name
143+
responses:
144+
2XX:
145+
content:
146+
application/json:
147+
schema:
148+
type: object
149+
properties:
150+
status:
151+
type: string
152+
required:
153+
- status
154+
4XX:
155+
$ref: '#/components/responses/Error'
126156
/self:
127157
get:
128158
responses:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import type { GlobalContext, OperationObject } from "../src/types.js";
2+
import transformOperationObject from "../src/transform/operation-object.js";
3+
4+
const ctx: GlobalContext = {
5+
additionalProperties: false,
6+
alphabetize: false,
7+
defaultNonNullable: false,
8+
discriminators: {},
9+
emptyObjectsUnknown: false,
10+
immutableTypes: false,
11+
indentLv: 0,
12+
operations: {},
13+
parameters: {},
14+
pathParamsAsTypes: false,
15+
postTransform: undefined,
16+
silent: true,
17+
supportArrayLength: false,
18+
transform: undefined,
19+
excludeDeprecated: false,
20+
};
21+
22+
describe("Operation Object", () => {
23+
it("allows 2XX codes", () => {
24+
const schema: OperationObject = {
25+
responses: {
26+
"2XX": {
27+
description: "OK",
28+
content: {
29+
"application/json": {
30+
schema: { type: "string" },
31+
},
32+
},
33+
},
34+
"4XX": {
35+
description: "OK",
36+
content: {
37+
"application/json": { schema: { $ref: 'components["schemas"]["Error"]' } },
38+
},
39+
},
40+
"5XX": {
41+
description: "OK",
42+
content: {
43+
"application/json": { schema: { $ref: 'components["schemas"]["Error"]' } },
44+
},
45+
},
46+
},
47+
};
48+
const generated = transformOperationObject(schema, { ctx, path: "#/paths/~get-item" });
49+
expect(generated).toBe(`{
50+
responses: {
51+
/** @description OK */
52+
"2XX": {
53+
content: {
54+
"application/json": string;
55+
};
56+
};
57+
/** @description OK */
58+
"4XX": {
59+
content: {
60+
"application/json": components["schemas"]["Error"];
61+
};
62+
};
63+
/** @description OK */
64+
"5XX": {
65+
content: {
66+
"application/json": components["schemas"]["Error"];
67+
};
68+
};
69+
};
70+
}`);
71+
});
72+
});

0 commit comments

Comments
 (0)