Skip to content

Commit 7698546

Browse files
feat: allow form data through default body serializer (#1762)
* feat: allow form data through default body serializer * chore: lint * test: send multipart/form-data with file * docs: openapi-fetch changeset patch * test: cast FormData to string instead of ts-ignore * chore: lint
1 parent f29205a commit 7698546

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

.changeset/warm-plums-wait.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"openapi-fetch": patch
3+
---
4+
5+
Allow FormData through defaultBodySerializer

packages/openapi-fetch/src/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,9 @@ export function defaultPathSerializer(pathname, pathParams) {
434434
* @type {import("./index.js").defaultBodySerializer}
435435
*/
436436
export function defaultBodySerializer(body) {
437+
if (body instanceof FormData) {
438+
return body;
439+
}
437440
return JSON.stringify(body);
438441
}
439442

packages/openapi-fetch/test/fixtures/api.d.ts

+40
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,46 @@ export interface paths {
814814
patch?: never;
815815
trace?: never;
816816
};
817+
"/multipart-form-data-file-upload": {
818+
parameters: {
819+
query?: never;
820+
header?: never;
821+
path?: never;
822+
cookie?: never;
823+
};
824+
get?: never;
825+
put?: never;
826+
post: {
827+
parameters: {
828+
query?: never;
829+
header?: never;
830+
path?: never;
831+
cookie?: never;
832+
};
833+
requestBody: {
834+
content: {
835+
"multipart/form-data": string;
836+
};
837+
};
838+
responses: {
839+
200: {
840+
headers: {
841+
[name: string]: unknown;
842+
};
843+
content: {
844+
"application/json": {
845+
text: string;
846+
};
847+
};
848+
};
849+
};
850+
};
851+
delete?: never;
852+
options?: never;
853+
head?: never;
854+
patch?: never;
855+
trace?: never;
856+
};
817857
}
818858
export type webhooks = Record<string, never>;
819859
export interface components {

packages/openapi-fetch/test/fixtures/api.yaml

+20
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,26 @@ paths:
470470
responses:
471471
200:
472472
$ref: "#/components/responses/MultipleResponse"
473+
/multipart-form-data-file-upload:
474+
post:
475+
requestBody:
476+
content:
477+
multipart/form-data:
478+
schema:
479+
type: string
480+
format: binary
481+
required: true
482+
responses:
483+
"200":
484+
content:
485+
application/json:
486+
schema:
487+
type: object
488+
properties:
489+
text:
490+
type: string
491+
required:
492+
- text
473493
components:
474494
schemas:
475495
Post:

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

+27
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,33 @@ describe("client", () => {
13521352
customProperty: "value",
13531353
});
13541354
});
1355+
1356+
it("multipart/form-data with a file", async () => {
1357+
const TEST_STRING = "Hello this is text file string";
1358+
1359+
const file = new Blob([TEST_STRING], { type: "text/plain" });
1360+
const formData = new FormData();
1361+
formData.append("file", file);
1362+
1363+
const client = createClient<paths>({ baseUrl });
1364+
useMockRequestHandler({
1365+
baseUrl,
1366+
method: "post",
1367+
path: "/multipart-form-data-file-upload",
1368+
handler: async (data) => {
1369+
// Get text from file and send it back
1370+
const formData = await data.request.formData();
1371+
const text = await (formData.get("file") as File).text();
1372+
return new HttpResponse(JSON.stringify({ text }));
1373+
},
1374+
});
1375+
const { data } = await client.POST("/multipart-form-data-file-upload", {
1376+
// TODO: how to get this to accept FormData?
1377+
body: formData as unknown as string,
1378+
});
1379+
1380+
expect(data?.text).toBe(TEST_STRING);
1381+
});
13551382
});
13561383

13571384
describe("responses", () => {

0 commit comments

Comments
 (0)