29

I am trying to send the content-type in my superagent post request to multipart/form-data.

var myagent = superagent.agent();

myagent
  .post('http://localhost/endpoint')
  .set('api_key', apikey)
  .set('Content-Type', 'multipart/form-data')
  .send(fields)
  .end(function(error, response){
    if(error) { 
       console.log("Error: " + error);
    }
  });

The error I get is: TypeError: Argument must be a string

If I remove the:

.set('Content-Type', 'multipart/form-data')

I don't get any error but my back end is receiving the request as content-type: application/json

How can I force the content type to be multipart/form-data so that I can access req.files()?

treecoder
  • 43,129
  • 22
  • 67
  • 91
nwkeeley
  • 1,397
  • 5
  • 18
  • 28
  • What happens if you try to do one of the examples from the [docs](http://visionmedia.github.com/superagent/#multipart-requests)? Try not setting the content type and repeatedly use the `field` as per the last example in that section. That may not be what you eventually want to implement but it could help debug what's wrong. – David Weldon Dec 13 '12 at 17:43

4 Answers4

38

First, you do not mention either of the following:

.set('Content-Type', 'multipart/form-data')

OR

.type('form')

Second, you do not use the .send, you use .field(name, value).

Examples

Let's say you wanted to send a form-data request with the following:

  • two text fields: name and phone
  • one file: photo

So your request will be something like this:

superagent
  .post( 'https://example.com/api/foo.bar' )
  .set('Authorization', '...')
  .accept('application/json')
  .field('name', 'My name')
  .field('phone', 'My phone')
  .attach('photo', 'path/to/photo.gif')

  .then((result) => {
    // process the result here
  })
  .catch((err) => {
    throw err;
  });

And, let's say you wanted to send JSON as a value of one of your fields, then you'd do this.

try {
  await superagent
         .post( 'https://example.com/api/dog.crow' )
         .accept('application/json')
         .field('data', JSON.stringify({ name: 'value' }))
}
catch ( ex ) {
    // .catch() stuff
}

// .then() stuff...
treecoder
  • 43,129
  • 22
  • 67
  • 91
  • For me, on the front end, `.attach('photo', 'path/to/photo.gif')` doesn't work, it gives an error: `parameter 2 is not of type 'Blob'` . I have to use the file descriptor instead, and then all is fine. – Will59 Aug 10 '20 at 23:17
16

Try .type('form') instead of .set('Content-Type', 'multipart/form-data')

See http://visionmedia.github.io/superagent/#setting-the-content-type

Flo Schild
  • 5,104
  • 4
  • 40
  • 55
risyasin
  • 1,325
  • 14
  • 24
  • It's not working anymore. I get MIME type application/x-www-form-urlencoded with type('form'). It's consistent with the doc. – Overdrivr Oct 27 '17 at 14:24
8

It is not clear what is in the fields variable that you are sending, but here is some information that may help you determine where your problem lies.

To begin with, if you are actually trying to build a multi-part request, this is the official documentation for doing so: http://visionmedia.github.com/superagent/#multipart-requests

as for the error that you got...

The reason is that during the process of preparing the request, SuperAgent checks the data to be sent to see if it is a string. If it is not, it attempts to serialize the data based on the value of the 'Content-Type', as seen below:

exports.serialize = {
  'application/x-www-form-urlencoded': qs.stringify,
  'application/json': JSON.stringify
};

which is used here:

// body
if ('HEAD' != method && !req._headerSent) {
  // serialize stuff
  if ('string' != typeof data) {
    var serialize = exports.serialize[req.getHeader('Content-Type')];
    if (serialize) data = serialize(data);
  }

  // content-length
  if (data && !req.getHeader('Content-Length')) {
    this.set('Content-Length', Buffer.byteLength(data));
  }
}

this means that to set a form 'Content-Type' manually you would use

.set('Content-Type', 'application/x-www-form-urlencoded')

or

.type('form') as risyasin mentioned

any other 'Content-Type' will not be serialized, and Buffer.byteLength(data) will subsequently throw the TypeError: Argument must be a string exception if the value of your fields variable is not a string.

Community
  • 1
  • 1
Chad
  • 2,161
  • 1
  • 19
  • 18
-2

Here is what worked for me. I had a single field form, that was uploading a file. I turned the form into a HTML5 FormData element and then did it as follows:

var frm = new FormData(document.getElementById('formId'));
var url =  'url/here';

superagent.post(url)                    
.attach('fieldInFormName', frm.get('fieldInFormName'))                                        
.end( function (error, response) {
    //handle response
});

Please note, I tried various ways of setting the 'Content-Type' manually in superagent, and it never worked correctly because of the multipart identifier needed in the Content-Type.

Burneh
  • 30
  • 2