Search code examples
javascriptxmlhttprequestmultipartform-dataform-data

How to make a formData with multiple files


I'm trying to make end to end test for my application, to do so we use a mock application to inject data for the front end

My problem is I have a controller in my spring boot application like this

@PostMapping("/data")
public String uploadCsv(@RequestParam("files") final MultipartFile[] files, final HttpServletResponse httpResponse) throws IOException {
    final List<MultipartFile> listFiles = Arrays.asList(files);
    // some functionnal code 
}

I can't use the IHM of the mock to insert data, but the form look like this :

<form name="uploadForm" method="post" enctype="multipart/form-data" action="/data">
    <input type="file" name="files" multiple/>
    <input type="submit" value="upload"/>
</form>

My problem here is with the multiple, as you can see, the controller wait for an array of multiparFile.

When I try to push my data, I can see with the debugger that I go in the controller method for the data but my array have a 0 size and can't get the data I need

Here is my code to submit my data :

let files =[];
let myFile = createFile();
files.push(myFile);
let data = new FormData();
data.append('files',files);
let XHR = new XMLHttpRequest();
XHR.open('POST', 'http://127.0.0.1:9000/data');
XHR.setRequestHeader('Content-Type', 'multipart/form-data;boundary=---------------------------7da24f2e50046');
XHR.setRequestHeader('Access-Control-Allow-Origin','*');
XHR.send(data);

as you can see, I've tried to create an array of File, or just insert my files but either way my array in my controller don't have anything inside

do you know how I can solve my problem ?

UPDATE :

I've tried it like this :

data.append('files[]',files);
sendFiles(data);

function sendFiles(formData) {
const options = {
method: "POST",
headers: {
  'Content-Type': 'multipart/form-data;boundary=---------------------------7da24f2e50046',
  'Access-Control-Allow-Origin': '*'
},
body: formData
};
return fetch('http://127.0.0.1:9000/data', options)
.then(response => console.log(response.data))
.catch(e => console.log('url is local not going to work'))
}

With and without [] for the 'files' part in the formdata

it was the same behavior as before, I go through my rest endpoint but with an empty multipart file

Because it's a function just to upload the file to the mock, I can't inject HTML into the page to create a form

The HTML above with input multiple is juste the example of how it work with the IHM, unfortunately I can't use this for my test because it's not the same application

UPDATE 2 :

I think my problem come from here, when I do my request with the function sendFiles, I can see in my network call this :

------WebKitFormBoundaryBCEt6Ivp0dW6OQ8y ... my form data ... ------WebKitFormBoundaryBCEt6Ivp0dW6OQ8y-- So there is a formBoundary which is generate, but it's not added into the headers, how can I get this WebKitFormBoundary to add it inside my httpHeaders ?


Solution

  • I finally solved my issue,

    when I was using an XmlHttpRequest, the request didn't add any boundaries into my request, that's why I added one

    When I switch to a fetch to my URL, a boundary was added in my request, so my file wasn't recognized by my backend, I just had to remove the boundary part on my request

    Another problems I had was with the empty file, it came from the way I was declaring it, to create a csv file you need to do something like this

    new File(['header;for;the;csv;\n','data;for;the;csv1\ndata;for;the;csv2\n?...'],'filename.csv',{    type: "text/csv"});
    

    As you can see, my array only have 2 entries, 1 for headers, one for data, and \n to return to the line

    I hope this will help someone in the futur!

    Thanks all !