Eric
Eric

Reputation: 2076

Node request module - trouble sending formdata

I'm trying to send a post request from my node server to an api that expects a file and other form data as an multipart/form-data.

Here is what my code looks like

var importResponse = function(csv){
  stringify(csv, function(err, output){
    request.post({
      headers: {'X-API-TOKEN':token, 'content-type' : 'multipart/form-data'},
      url: url,
      formData: {
        surveyId: surveyId,
        file: {
            value: output,
            options: {
                fileName: 'test.csv',
                contentType:'text/csv'
            }
        }
      }
    }, function(error, response, body){
      console.log(body);
    });
  });
}

Using request-debug here is the request:

request:
   { debugId: 1,
     uri: 'https://co1.qualtrics.com/API/v3/responseimports',
     method: 'POST',
     headers:
      { 'X-API-TOKEN': 'removed',
        'content-type':
         'multipart/form-data; boundary=--------------------------010815605562947295265820',
        host: 'co1.qualtrics.com',
        'content-length': 575 } } }

and the response:

response:
   { debugId: 1,
     headers:
      { 'content-type': 'application/json',
        'content-length': '188',
        'x-edgeconnect-midmile-rtt': '28',
        'x-edgeconnect-origin-mex-latency': '56',
        date: 'Wed, 18 Jul 2018 03:57:59 GMT',
        connection: 'close',
        'set-cookie': [Array],
        'strict-transport-security': 'max-age=31536000; includeSubDomains; preload' },
     statusCode: 400,
     body:
      '{"meta":{"httpStatus":"400 - Bad Request","error":{"errorMessage":"Missing Content-Type for file part. name=file","errorCode":"MFDP_3"},"requestId":"322a16db-97f4-49e5-bf10-2ecd7665972e"}}' } }

The error I'm getting is: Missing Content-Type for file part.

I've added this in the options:

options: {
    fileName: 'test.csv',
    contentType:'text/csv'
}

When I look at the request, it seems as though the form data isn't included. But perhaps that is just the request-debug not showing it.

I saw a similar SO question and the answer was to use JSON.stringify. I tried changing my code to the following:

request.post({
  headers: {'X-API-TOKEN':token, 'content-type' : 'multipart/form-data'},
  url: url,
  body: JSON.stringify({
    surveyId: surveyId,
    file: {
        value: output,
        options: {
            fileName: 'test.csv',
            contentType:'text/csv'
        }
    }
  })

However, I got the following error:

{"meta":{"httpStatus":"400 - Bad Request","error":{"errorMessage":"Missing boundary header"}}}

What am I doing wrong?

UPDATE When I tried changing the file value to a csv on my computer fs.createReadStream('test.csv'), it worked fine

    file: {
        value: fs.createReadStream('test.csv'),
        options: {
            contentType: 'text/csv'
        }
    }

So I assume there is something wrong with the way I'm giving the file. The output variable that I'm using as the file just looks like "QID1,QID2\nQID1,QID2\n1,2". I assume this is causing the problems, even though the error is a bit misleading. I tried creating a Readable that I found as a StackOverFlow answer like so:

var s = new Readable
s.push(output)
s.push(null) 

However, this lead to a Unexpected end of input

{"meta":{"httpStatus":"400 - Bad Request","error":{"errorMessage":"Unexpected end of input"}}}

Upvotes: 2

Views: 2114

Answers (4)

Eric
Eric

Reputation: 2076

I found the issue. My first solution was fine, but instead of fileName it should have been filename

var importResponse = function(csv){
  stringify(csv, function(err, output){
    request.post({
      headers: {'X-API-TOKEN':token, 'content-type' : 'multipart/form-data'},
      url: url,
      formData: {
        surveyId: surveyId,
        file: {
            value: output,
            options: {
                filename: 'test.csv', //filename NOT fileName
                contentType:'text/csv'
            }
        }
      }
    }, function(error, response, body){
      console.log(body);
    });
  });
}

Upvotes: 2

Mohammad Raheem
Mohammad Raheem

Reputation: 1157

Hey Eric check in which format they accept multipartRequest ,as I did for uploading the file on drive like this:

        request(options, function (err, response) {
            var boundary = '-------314159265358979323846';
            var delimiter = "\r\n--" + boundary + "\r\n";
            var close_delim = "\r\n--" + boundary + "--";

            var fileContent = 'Sample upload :)';

            var metadata = {
                'name': 'myFile.txt',
                'mimeType': 'text/plain\r\n\r\n'
            };

            var multipartRequestBody = delimiter + 'Content-Type: application/json\r\n\r\n' + JSON.stringify(metadata) + delimiter + 'Content-Type: ' + 'text/plain\r\n\r\n' + fileContent + close_delim;

            request(options, function (err, response) {
                var url = 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&access_token=' + JSON.parse(response.body).access_token;
                var options = {
                    method: 'POST',
                    url: url,
                    headers: {
                        'Content-Type': 'multipart/related; boundary="' + boundary + '"'
                    },
                    body: multipartRequestBody
                };

                request(options, function (err, response) {
                    res.send({resultdata: response.body});
                });
            });
        });

Set the multi-part as per your endpoint accepting.

Upvotes: 1

Anthony Morris
Anthony Morris

Reputation: 51

Is it possible that you are using the incorrect property name for your file?

A quick read of the forms info for the request Node module makes me think you should be using custom_file instead of file.

You can read more about it here: https://github.com/request/request#forms

Upvotes: 1

Sachin S
Sachin S

Reputation: 196

Using frameworks like express(they automatically parse headers and response) and npm modules like multer for handling multipart form data helps cause they do all the heavy lifting for you

Upvotes: 0

Related Questions