How do I encode an array in a form field in NodeJS' request?

1.9k views Asked by At

I'm using an API that requires me to put an array in a form field. The example given is in PHP, but I'm using NodeJS. The API expects one of the fields to be an array, and I'm having a hard time figuring out how to do this.

The PHP example looks like this:

$request->buildPostBody(array(
 'reference' => array(
 'line1' => 'Soundboard Setup',
 'line2' => 'Thank you for the order',
 'line3' => 'Our reference is: 3993029/11BD'
 ),
 'lines' => array(
 array('amount' => 50,
 'amount_desc' => 'panels',
 'description' => 'Sound buttons',
 'tax_rate' => 21,
 'price' => 5.952
 ),
 array('amount' => 1,
 'amount_desc' => '',
 'description' => 'Wooden case',
 'tax_rate' => 21,
 'price' => 249
 ),
 array('amount' => 10,
 'amount_desc' => 'hours',
 'description' => 'Support',
 'tax_rate' => 6,
 'price' => 62.5
 ),
 array('description' => 'This is a textline'))
));

In NodeJS it I've tried this (among other things):

var formData = {
  reference: [{'line1':'something'}], // <- this isn't going to fly
  lines: [{
    'amount': amount,
    'amount_desc': 'amount_desc',
    'description': 'description',
    'tax_rate': 0,
    'price': 100
  }]
};

request.post({
    url: 'https://www.factuursturen.nl/api/v1/invoices/',
    formData: formData,
    headers: {
      'Authorization': 'Basic ' + new Buffer(user + ':' + key).toString('base64')
    }
  }, function (error, response, body) {
    if (!error && [200, 201, 204].indexOf(response.statusCode) > 0) {
      console.log('posted ': ', response.statusCode);
    } else {
      console.log('problem with request: ', error, response.statusCode, body);
    }
  }
);

When I try to pass an object like so: reference: {'line1':'foo'} I get an error from Node:

node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js:33
  source.on('error', function() {});
         ^
TypeError: Object #<Object> has no method 'on'

How would I best go about shoehorning this round peg into that square hole?

1

There are 1 answers

3
laggingreflex On BEST ANSWER

In PHP arrays can be arrays and they can be associative arrays, which are essentially objects in JavaScript.

Specifying with array()

An array can be created using the array() language construct. It takes any number of comma-separated key => value pairs as arguments.

array(
    key  => value,
    key2 => value2,
    key3 => value3,
    ...
)

In JavaScript the above would essentially be just an object

{
    key: 'value',
    key2: 'value2'
    key3: 'value3'
    ...
}

It will not be an object wrapped inside an array [{…}], which is what you're doing with your reference

So to mimic the PHP structures your data should be like this:

var formData = {
  reference: {'line1':'something'}, // <- this should work now
  lines: [{  // <- this is still an array of objects [{}], as in PHP too, it's a nested array
    amount: amount,
    'amount_desc': 'amount_desc',
    'description': 'description',
    'tax_rate': 0,
    'price': 100
  }]
};

But that causes another problem as you have noticed.


When I try to pass an object like so: reference: {'line1':'foo'} I get an error from Node:

node_modules/request/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js:33
  source.on('error', function() {});
         ^
TypeError: Object #<Object> has no method 'on'

This error is explain here: https://github.com/request/request/issues/1495 Basically form-data only takes simple object probably only 1 level deep.

Try this:

var formData = {
  'reference.line1': 'something',
  'lines[0].amount': amount,
  'lines[0].amount_desc': 'amount_desc',
  'lines[0].description': 'description',
  'lines[0].tax_rate': 0,
  'lines[0].price': 100,
};