title: Uploading a file with FormData and multer
body: <p>I have successfully managed to upload a file to a Node server using the <code>multer</code> module by selecting the file using the input file dialog and then by submitting the form, but now I would need, instead of submitting the form, to create a <code>FormData</code> object, and send the file using <code>XMLHttpRequest</code>, but it isn't working, the file is always <code>undefined</code> at the server-side (router).</p>
  
  <p>The function that does the AJAX request is:</p>
  
  <pre><code>function uploadFile(fileToUpload, url) {
  
    var form_data = new FormData();
  
    form_data.append('track', fileToUpload, fileToUpload.name);
  
    // This function simply creates an XMLHttpRequest object
    // Opens the connection and sends form_data
    doJSONRequest("POST", "/tracks/upload", null, form_data, function(d) {
      console.log(d);
    })
  
  }
  </code></pre>
  
  <p>Note that <code>fileToUpload</code> is defined and the <code>url</code> is correct, since the correct router method is called. <code>fileToUpload</code> is a <code>File</code> object obtained by dropping a file from the filesystem to a dropzone, and then by accessing the <code>dataTransfer</code> property of the drop event. </p>
  
  <p><code>doJSONRequest</code> is a function that creates a <code>XMLHttpRequest</code> object and sends the file, etc (as explained in the comments).</p>
  
  <pre><code>function doJSONRequest(method, url, headers, data, callback){
  
    //all the arguments are mandatory
    if(arguments.length != 5) {
      throw new Error('Illegal argument count');
    }
  
    doRequestChecks(method, true, data);
  
    //create an ajax request
    var r = new XMLHttpRequest();
  
    //open a connection to the server using method on the url API
    r.open(method, url, true);
  
    //set the headers
    doRequestSetHeaders(r, method, headers);
  
    //wait for the response from the server
    r.onreadystatechange = function () {
      //correctly handle the errors based on the HTTP status returned by the called API
      if (r.readyState != 4 || (r.status != 200 &amp;&amp; r.status != 201 &amp;&amp; r.status != 204)){
        return;
      } else {
        if(isJSON(r.responseText))
          callback(JSON.parse(r.responseText));
        else if (callback !== null)
          callback();
      }
    };
  
    //set the data
    var dataToSend = null;
    if (!("undefined" == typeof data) 
      &amp;&amp; !(data === null))
      dataToSend = JSON.stringify(data);
  
    //console.log(dataToSend)
  
    //send the request to the server
    r.send(dataToSend);
  }
  </code></pre>
  
  <p>And here's <code>doRequestSetHeaders</code>:</p>
  
  <pre><code>function doRequestSetHeaders(r, method, headers){
  
    //set the default JSON header according to the method parameter
    r.setRequestHeader("Accept", "application/json");
  
    if(method === "POST" || method === "PUT"){
      r.setRequestHeader("Content-Type", "application/json");
    }
  
    //set the additional headers
    if (!("undefined" == typeof headers) 
      &amp;&amp; !(headers === null)){
  
      for(header in headers){
        //console.log("Set: " + header + ': '+ headers[header]);
        r.setRequestHeader(header, headers[header]);
      }
  
    }
  }
  </code></pre>
  
  <p>and my router to upload files is the as follows</p>
  
  <pre><code>// Code to manage upload of tracks
  var multer = require('multer');
  var uploadFolder = path.resolve(__dirname, "../../public/tracks_folder");
  
  function validTrackFormat(trackMimeType) {
    // we could possibly accept other mimetypes...
    var mimetypes = ["audio/mp3"];
    return mimetypes.indexOf(trackMimeType) &gt; -1;
  }
  
  function trackFileFilter(req, file, cb) {
    cb(null, validTrackFormat(file.mimetype));
  }
  
  var trackStorage = multer.diskStorage({
    // used to determine within which folder the uploaded files should be stored.
    destination: function(req, file, callback) {
  
      callback(null, uploadFolder);
    },
  
    filename: function(req, file, callback) {
      // req.body.name should contain the name of track
      callback(null, file.originalname);
    }
  });
  
  var upload = multer({
    storage: trackStorage,
    fileFilter: trackFileFilter
  });
  
  
  router.post('/upload', upload.single("track"), function(req, res) {
    console.log("Uploaded file: ", req.file); // Now it gives me undefined using Ajax!
    res.redirect("/"); // or /#trackuploader
  });
  </code></pre>
  
  <p>My guess is that <code>multer</code> is not understanding that <code>fileToUpload</code> is a file with name <code>track</code> (isn't it?), i.e. the middleware <code>upload.single("track")</code> is not working/parsing properly or nothing, or maybe it simply does not work with <code>FormData</code>, in that case it would be a mess. What would be the alternatives by keeping using multer?</p>
  
  <p>How can I upload a file using AJAX and multer?</p>
  
  <p>Don't hesitate to ask if you need more details.</p>