Clément Vgnc Clément Vgnc - 5 months ago 28
Ajax Question

Asynchronous form-data POST request with xmlhhtprequest

I am trying to upload a file to the REST Api of Octoprint, which should be done by sending a POST request with

Content-Type: multipart/form-data

(http://docs.octoprint.org/en/master/api/fileops.html#upload-file)

I am using NodeJS and two libraries, XmlHttpRequest and form-data. When trying:

var xhr = new xmlhttprequest() ;
var form = new formData() ;
form.append('exampleKey', 'exampleValue');
xhr.open("POST","octopi.local/api/local", true) ;
xhr.setRequestHeader("Content-Type","multipart/form-data") ;
xhr.send(form) ;


I get an error at the xhr.send line :

TypeError: first argument must be a string or Buffer


If I make a synchronous request by using xhr.open("POST",url,false), this error disappears.

Why is it so ? Is there a way to turn it into an asynchronous request ?

EDIT Actually, I don't really understand the documentation. I suppose that I should set the file I want to upload by using
form.append("filename", filepath, "exampleName")
, but I am not sure about that. The fact is that I noticed that I get the TypeError even if I try a simplified request, without sending any file.

EDIT2 This is the modified code, which returns the same error :

var XMLHttpRequest=require('xmlhttprequest').XMLHttpRequest ;
var FormData = require('form-data');

var data = new FormData();
data.append("key","value" );

var xhr = new XMLHttpRequest();
xhr.open('POST', "octopi.local/api/files/");
xhr.send(data);

Answer

After a long time working on this, I finally managed to upload a file. If you use NodeJS, don't rely on the MDN documentation: it tells what the libraries should do, not what they can actually do on the node platform. You should only focus on the docs available on GitHub.

It seems that it is not currently possible to send a form with XMLHttpRequest : I tried using JSON.stringify(form) but then wireshark tells me that the request is not a multipart/formdata request.

If you want to upload a file, you should rather use the 'request' module. The following has worked for me :

exports.unwrappeduploadToOctoprint = function(){
  "use strict" ;
  var form ={
    file: {
           value: fs.readFileSync(__dirname+'/test2.gcode'),
           options: { filename: 'test2.gcode'}
         }
  };

  var options = {
    method: 'POST',
    url: 'http://192.168.1.24/api/files/local',
    headers: { 'x-api-key': 'E0A2518FB11B40F595FC0068192A1AB3'},
    formData: form
  };

  var req = request(options, function (error, response, body) {
    if (error) throw new Error(error);
    console.log(body);
  });
};
Comments