Superagent: Send & Attach Are Incompatible.

Created on 6 Nov 2012  Â·  10Comments  Â·  Source: visionmedia/superagent

I was able to get around this by using the low level part() API, but...

When you send form data and have one or more attachments superagent explodes with an obscure "Argument Must be String" error. This is because the content-type gets set to multipart, and there is no multipart formatter to convert it to string, it tries to do a Byte Length operation on the raw JSON to set the content-length.

In fact if you skip that error condition it will send the attachment correctly, but ignore the form-data.

describe '/worms', () ->
  describe 'POST', () ->
    it 'should respond with JSON', (done) ->
      worm = _.first fixtures.worms()
      delete worm.image_url
      delete worm.location
      console.dir 
      supertest(app)
        .post('/worms')
        .attach('image', wormImage)
        .send(worm)
        .expect(400)
        .set('accept', 'application/json')
        .expect('content-type', 'application/json')
        .end (err, res) ->
          throw err if err
          console.dir res.body
          done()

✖ 1 of 1 test failed:

1) /worms POST should respond with JSON:
TypeError: Argument must be a string
at Test.Request.end (/Users/vanalsti/Projects/citizen-science-api/node_modules/supertest/node_modules/superagent/lib/node/index.js:607:43)
at Test.end (/Users/vanalsti/Projects/citizen-science-api/node_modules/supertest/lib/test.js:121:7)
at Context. (/Users/vanalsti/Projects/citizen-science-api/tests/server.coffee:29:173)
at Test.Runnable.run (/Users/vanalsti/nvm/v0.8.14/lib/node_modules/mocha/lib/runnable.js:187:15)
at Runner.runTest (/Users/vanalsti/nvm/v0.8.14/lib/node_modules/mocha/lib/runner.js:307:10)
at Runner.runTests.next (/Users/vanalsti/nvm/v0.8.14/lib/node_modules/mocha/lib/runner.js:353:12)
at next (/Users/vanalsti/nvm/v0.8.14/lib/node_modules/mocha/lib/runner.js:235:14)
at Runner.hooks (/Users/vanalsti/nvm/v0.8.14/lib/node_modules/mocha/lib/runner.js:244:7)
at next (/Users/vanalsti/nvm/v0.8.14/lib/node_modules/mocha/lib/runner.js:192:23)
at Runner.hook (/Users/vanalsti/nvm/v0.8.14/lib/node_modules/mocha/lib/runner.js:212:5)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)

A less obscure error would be nice. Even nicer would be if send and attach could be compatible.

Most helpful comment

Request.field() only accepts string values. What's the recommended method for including json in a multipart request and Request.attach() for images?

All 10 comments

yeah you have to use .field() for multipart, send() could possibly utilize this if it knows it's multipart

Thanks. I'll play with field the next time I'm in that project. Is there a better source for documentation then the README.MD or should I be writing a patch to improve it?

closing for now

Request.field() only accepts string values. What's the recommended method for including json in a multipart request and Request.attach() for images?

we only do multipart/form-data at the moment, so we can't put json in, we could eventually do multipart/mixed or something but then things like formidable will fail

but it would be nice to have .fields(object) or something similar that invokes .field() a bunch

I combined .field and .attach in my test in order to test sending json with an image. Here's an example:

var should = require('should'),
supertest = require('supertest');
var request = supertest('localhost:3000');

describe('upload', function() {
it('a file', function(done) {
api.post('/your/endpoint')
.field('extra_info', '{"in":"case you want to send json along with your file"}')
.attach('image', 'path/to/file.jpg')
.end(function(err, res) {
res.should.have.status(200) // 'success' status
done()
});
});
});

Take a look at http://stackoverflow.com/questions/10120866/how-to-unit-test-with-a-file-upload-in-mocha

I want to access 'extra_info' data (based on above example) in my expressJS app.
How to access it?
Because I am not getting any 'extra_info' field in 'req.body'.

but it would be nice to have .fields(object) or something similar that invokes .field() a bunch

I tested this and is working....

const superagent = require("superagent");
!superagent.Request.prototype.fields && Object.defineProperty(superagent.Request.prototype, "fields",
{
value: function(items) {

  if (items && typeof items === "object") {

    for (let key in items) {

      if (items.hasOwnProperty(key)) {

        let item = items[key];

        if (typeof item === "function") continue;
        else if (typeof item === "object") {
          item = JSON.stringify(item);
        }

        this.field(key, item);
      }
    }
  }

  return this;
}

});
`

Was this page helpful?
0 / 5 - 0 ratings

Related issues

littlee picture littlee  Â·  8Comments

tj picture tj  Â·  9Comments

ariemeow picture ariemeow  Â·  8Comments

djizco picture djizco  Â·  5Comments

kornelski picture kornelski  Â·  9Comments