Support "req.formData()"
Prerequisites
- [X] I confirm my issue is not in the opened issues
- [X] I confirm the Frequently Asked Questions didn't contain the answer to my issue
Environment check
- [X] I'm using the latest
mswversion - [X] I'm using Node.js version 14 or higher
Node.js version
16.13.0
Reproduction repository
https://github.com/ddolcimascolo/msw-issue-1327
Reproduction steps
Axios to send a POST request with a FormData body. Try to use req.body in the handler
Current behavior
TypeError: The "input" argument must be an instance of ArrayBuffer or ArrayBufferView. Received an instance of FormData
at new NodeError (node:internal/errors:371:5)
at TextDecoder.decode (node:internal/encoding:413:15)
at decodeBuffer (/data/dev/msw-issue-formdata/node_modules/@mswjs/interceptors/src/utils/bufferUtils.ts:11:18)
at RestRequest.get body [as body] (/data/dev/msw-issue-formdata/node_modules/msw/src/utils/request/MockedRequest.ts:117:18)
Expected behavior
Maybe req.formData() as per https://developer.mozilla.org/en-US/docs/Web/API/Request/formData would be the way to go?
I am using a custom fetcher with codegen to handle FormData mutations and have never had much luck getting it to work in msw so have been intercepting the request at the point where my data is submitted in my tests like this:
// Intercept the upload
server.use(
rest.post(
"http://localhost:8000/fleetportalapi/graphiql",
(req, res, ctx) =>
res(
ctx.json({
data: {
fileUploadMileage: {
__typename: "FileUploadMileageError",
errorMessage: "Error parsing the CSV file.",
},
},
})
)
)
);
This is not perfect - ideally I would be able to use graphql.mutation - but it was working fine until I updated to 0.44.0 today where I now get the same error:
console.error
The "input" argument must be an instance of ArrayBuffer or ArrayBufferView. Received an instance of FormData
at node_modules/msw/src/handlers/GraphQLHandler.ts:155:26
at tryCatch (node_modules/msw/src/utils/internal/tryCatch.ts:9:5)
at GraphQLHandler.parse (node_modules/msw/src/handlers/GraphQLHandler.ts:153:12)
at GraphQLHandler.test (node_modules/msw/src/handlers/RequestHandler.ts:167:12)
at node_modules/msw/src/utils/getResponse.ts:31:20
at Array.filter (<anonymous>)
at getResponse (node_modules/msw/src/utils/getResponse.ts:30:37)
FWIW my custom fetch looks like this (mostly borrowed from graphql-request:
import { extractFiles, isExtractableFile } from "extract-files";
const createRequestBody = <TVariables>(
query: string,
variables?: TVariables
) => {
const { files, clone } = extractFiles(
{ query, variables },
"",
isExtractableFile
);
if (files.size === 0) {
return JSON.stringify({ query, variables });
}
const form = new FormData();
form.append("operations", JSON.stringify(clone));
const map: { [key: number]: string[] } = {};
let i = 0;
files.forEach((paths) => {
map[++i] = paths;
});
form.append("map", JSON.stringify(map));
i = 0;
files.forEach((paths, file) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
form.append(`${++i}`, file as any);
});
return form as FormData;
};
export const useFetchData = <TData, TVariables>(
query: string,
options?: RequestInit["headers"]
): ((variables?: TVariables) => Promise<TData>) => {
return async (variables?: TVariables) => {
const body = createRequestBody(query, variables);
const res = await fetch(url, {
method: "POST",
headers: {
...(typeof body === "string"
? { "Content-Type": "application/json" }
: {}),
...(options ?? {}),
},
body,
});
const json = await res.json();
if (json.errors) {
const { message } = json.errors[0] || "Error..";
throw new Error(message);
}
return json.data;
};
};
My issue would be solved if msw could handle these kind of requests. For now I'll roll back to 0.42.1.
@ddolcimascolo Can you provide reproduction code for this error?
@95th I didn't forget, but facing some other troubles atm. If you want to give it a try it's really just
- Send a request with axios using a
FormDatabody to an URL mocked with MSW - Access
req.bodyin the request handler
Was working fine in the previous minor.
Cheers, David
@ddolcimascolo I tried this but its working fine for me. any special data included in the FormData?
Nothing special.
But I realize I have not given many details about the context... Were doing Jest tests with jsdom, so the FormData is what jsdom provides... Maybe it's the culprit but this was running smoothly before.
I'll definitely work on reproducing this in a repo
Having same issue, can't pull file off with req.body.get("file"). Worked in previous versions.
const file = new File(["test"], "test.bad");
const formData = new FormData();
formData.append("file", file);
fetch("/api/uploadFile", {
body: formData,
method: "POST",
})
rest.post(
"/api/uploadFile",
(req: MockedRequest<FormData>, res, ctx) => {
const file = req.body.get("file"); // fails here, hangs
...
}
)
Works in 0.43.1, stops working in 0.44.0+
Thx @nathanhannig. I didn't manage to create a full reproduction repo, yet.
@95th @nathanhannig I finally created the reproduciton repo @ https://github.com/ddolcimascolo/msw-issue-1327
Guys, any news?
@ddolcimascolo, no news so far. Anybody is welcome to take the reproduction repo above and step through this body function to find out what happens now with FormData bodies. Debugging this is about 80% of solving it.
on 0.44.2 ->
I can read FormData from req.body, however it's not a FormData object, but instead a json representation - so I grab the file via req.body.file rather than req.body.get('file')

Request data

text() => gives the value of text2 in that debugger
json() => throws (since its not json)
At some point it does seem like the file gets corrupted in 'upload' but I haven't gotten into where/how that could be improved/changed
Can that corruption be related to #1158 somehow?
Hi everyone, still no fix to this issue? We're stuck a few versions behind because of this... Can you advise if this would be doable by someone that never contributed to msw? Is this a good first issue?
Cheers, David
I have been stuck at 0.43.1 because of this isse
req.body was broken after that version (even though it incorrectly says it was depreciated)
Welcome aboard 🙄
req.body was broken after that version (even though it incorrectly says it was depreciated)
Hence why we've released it as a breaking change. It is getting deprecated, but it also drops some of the request reading methods since we didn't have the capacity to implement all of them.
Can you advise if this would be doable by someone that never contributed to msw? Is this a good first issue?
I don't see why it wouldn't be. This is a scoped known change, and you have previous versions that supported this to verify your implementation against.
How can I contribute?
- A/B what's going wrong with a
FormDatarequest body (req.body) in the resolver between 0.43.0 and 0.47.0. The fix will depend on the root cause: what exactly goes off? It may be useful to see how we parsed the request body before. - Add the
FormDatacase handling to the.bodymethod here. If applicable, we can also addMockedRequest.formData()method and reuse it in the deprecated.bodyproperty.
The main task here is to determine how we used to handle FormData request bodies in the past. I honestly don't recall. I don't think we used polyfills for that, it must've been something else. If we could bring that something else back into .body it'd be great.
Volunteers are certainly welcome. I will help with the code review so we could ship this feature in a timely manner.
Hey guys, my tentative in https://github.com/mswjs/msw/pull/1422
@kettanaito Did you get a chance to review the PR?
Cheers, David
Hey, @ddolcimascolo. Yes, thank you so much for opening it. I've left a few comments and I'd love to know your thoughts on those.
Also, it's worth mentioning that #1404 change is going to introduce .formData() as well but I don't think it's going to happen that fast.
@kettanaito Thx for the feedback. I dropped Axios in favor of a raw XHR request but I have no clue how to handle your comment about FormData not existing in Node...
I guess I stay on 0.38.1 until you implement the body getter...
@boryscastor, the body getter is not coming back. Instead, in the next major release you will be able to read the request's body as form data like you would do in regular JavaScript:
rest.post('/login', async ({ request }) => {
const data = await request.formData()
const email = data.get('email')
})
When is this coming out? Sometime this year, hopefully.
When can I try this? You can try this right now. More details in #1464.
what's the workaround until req.formData() exists?
Can I do something manually to get the data from req.arrayBuffer()?
const arrayBuffer = await req.arrayBuffer();
const formData = undefined; // ??;
@fibonacid, the FormData request body is actually a string in a predefined format:
const formData = new FormData()
formData.set('foo', 'bar')
const request = new Request('/url', { method: 'PUT', body: formData })
await request.text()
'------WebKitFormBoundaryY2WwRDBYmRbAKyLB\r\nContent-Disposition: form-data; name="foo"\r\n\r\nbar\r\n------WebKitFormBoundaryY2WwRDBYmRbAKyLB--\r\n'
You can read the request body as text to obtain that string. Then, you can feed it to any parser that would turn it back into a FormData instance. Unfortunately, the standard FormData constructor doesn't support that string as an input. You'd have to use third-party packages to do the job here.
You can use parse-multipart-data to parse that string into an object and then construct a FormData instance using that object.
Alternatively, consider switching to msw@next that ships with FormData built-in. More on that version here: #1464.
@kettanaito thanks, this is very helpful!
Came across this thread after facing 2 issues with MSW - all my graphql handlers throwing input instance of arraybuffer whenever i used formdata, and NetworkError when trying to access a body that was formdata. Will migrate to @next and give that a go. Thanks for the detailed migration guide, that'll save us a lot of time. Will edit this if it solves all of my problems
Released: v2.0.0 🎉
This has been released in v2.0.0!
Make sure to always update to the latest version (npm i msw@latest) to get the newest features and bug fixes.
Predictable release automation by @ossjs/release.