diff --git a/.changeset/warm-plums-wait.md b/.changeset/warm-plums-wait.md new file mode 100644 index 000000000..00361e0e8 --- /dev/null +++ b/.changeset/warm-plums-wait.md @@ -0,0 +1,5 @@ +--- +"openapi-fetch": patch +--- + +Allow FormData through defaultBodySerializer diff --git a/packages/openapi-fetch/src/index.js b/packages/openapi-fetch/src/index.js index cdcc3052e..e878ef0b8 100644 --- a/packages/openapi-fetch/src/index.js +++ b/packages/openapi-fetch/src/index.js @@ -434,6 +434,9 @@ export function defaultPathSerializer(pathname, pathParams) { * @type {import("./index.js").defaultBodySerializer} */ export function defaultBodySerializer(body) { + if (body instanceof FormData) { + return body; + } return JSON.stringify(body); } diff --git a/packages/openapi-fetch/test/fixtures/api.d.ts b/packages/openapi-fetch/test/fixtures/api.d.ts index cad5160d4..b1675777c 100644 --- a/packages/openapi-fetch/test/fixtures/api.d.ts +++ b/packages/openapi-fetch/test/fixtures/api.d.ts @@ -814,6 +814,46 @@ export interface paths { patch?: never; trace?: never; }; + "/multipart-form-data-file-upload": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "multipart/form-data": string; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + text: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { diff --git a/packages/openapi-fetch/test/fixtures/api.yaml b/packages/openapi-fetch/test/fixtures/api.yaml index 8994e1ba8..011fcc768 100644 --- a/packages/openapi-fetch/test/fixtures/api.yaml +++ b/packages/openapi-fetch/test/fixtures/api.yaml @@ -470,6 +470,26 @@ paths: responses: 200: $ref: "#/components/responses/MultipleResponse" + /multipart-form-data-file-upload: + post: + requestBody: + content: + multipart/form-data: + schema: + type: string + format: binary + required: true + responses: + "200": + content: + application/json: + schema: + type: object + properties: + text: + type: string + required: + - text components: schemas: Post: diff --git a/packages/openapi-fetch/test/index.test.ts b/packages/openapi-fetch/test/index.test.ts index 687bdc957..0055dcba7 100644 --- a/packages/openapi-fetch/test/index.test.ts +++ b/packages/openapi-fetch/test/index.test.ts @@ -1352,6 +1352,33 @@ describe("client", () => { customProperty: "value", }); }); + + it("multipart/form-data with a file", async () => { + const TEST_STRING = "Hello this is text file string"; + + const file = new Blob([TEST_STRING], { type: "text/plain" }); + const formData = new FormData(); + formData.append("file", file); + + const client = createClient({ baseUrl }); + useMockRequestHandler({ + baseUrl, + method: "post", + path: "/multipart-form-data-file-upload", + handler: async (data) => { + // Get text from file and send it back + const formData = await data.request.formData(); + const text = await (formData.get("file") as File).text(); + return new HttpResponse(JSON.stringify({ text })); + }, + }); + const { data } = await client.POST("/multipart-form-data-file-upload", { + // TODO: how to get this to accept FormData? + body: formData as unknown as string, + }); + + expect(data?.text).toBe(TEST_STRING); + }); }); describe("responses", () => {