10

I'm trying to send as formData, a stream from an image I get using request

The problem is that the request is fire after the formData request. Is there any way I can pipe the image request to recognize? but with the freedom of adding parameters to the formData?

e.g:

var req = request({
  method: 'POST',
  url: 'http://www.foo.bar/api/v1/tag/recognize',
  formData: {
    image_file: request('http://visual-recognition-demo.mybluemix.net/images/horses.jpg'),
    param2: 'value2'
  },
  json: true,
});

How do I fire:

request('http://visual-recognition-demo.mybluemix.net/images/horses.jpg') so the response can be used in req

UPDATE: Seems like the Content-Length header is missing in the
http://visual-recognition-demo.mybluemix.net/images/horses.jpg response
and you only get Transfer-Encoding: chunked

More details here

German Attanasio
  • 22,217
  • 7
  • 47
  • 63
  • I'm not sure that the `request` library would allow you to this via piping but instead you'd just have to use a callback with the body returned from the original request. – Explosion Pills Mar 13 '15 at 19:55
  • I think this should be handle in the request library. It happens when you don't specify `content-length` in the first response – German Attanasio Mar 31 '15 at 14:46

1 Answers1

8

Take a look this part of the docs. What you're describing is essentially this block

request.get('http://google.com/img.png').pipe(request.put('some_url'));  

Note the docs

When doing so, content-type and content-length are preserved in the PUT headers.

Also note, request will always return a Stream if you don't specify a callback. If you do provide a callback it tries to convert the response to a String. Use the encoding:null to get it to return raw bytes.
Example -

request({
   url: 'some_url', //your image
   encoding: null  //returns resp.body as bytes
}, callback..)

To chain calls together (run one after the other) , you can nest the callbacks or use promises. For example to run a request after another request completes -

var request = require('request');

//1st
request('first_url', function (error, response, body) {
  if (!error && response.statusCode == 200) {

      //2nd
      request('other_url', function (error, response, body) {   
         //process resp
      });
  }
});  

Or even better, convert the request callback code to Promises. See a promise library like Bluebird on how to do this.

Here's an example with bluebird (uses then to work in an iterative fasion)

var Promise = require("bluebird");
Promise.promisifyAll(require("request"));

request.getAsync('some_url').then(function(resp) {
   request.getAsync('some_other_url').then(..processing code..);
});
Justin Maat
  • 1,965
  • 3
  • 23
  • 33
  • Thanks for the examples and the explanation. If you look at [visual recognition](https://github.com/watson-developer-cloud/nodejs-wrapper/blob/master/services/visual_recognition/v1.js#L67) service implementation. How do you think I can implement your solution? I want to hide from users the problem of chaining calls. They should use the snippet I'm using for this question. – German Attanasio Mar 31 '15 at 19:20
  • If you want the users to be able to pipe in a binary object from an ajax request (say request lib or whatever), you would need to do a refactor of the actual implementation logic of how params is used. You should also (my suggestion) make the usage of a piped in resource be very explicit in the docs. Just taking a glance at your library I would never expect to be able to use an asynchronous response as a parameter (regardless if it was raw bytes or not) – Justin Maat Mar 31 '15 at 19:26
  • Basically I just provided an answer of how to chain a promise (using bytes or text response), so you can implement yourself. The above answer explains the process using the request library. But ideally I would think you wouldn't allow a response to be input as a parameter; or if you do, update the docs to very clearly show that option. – Justin Maat Mar 31 '15 at 19:28
  • Try playing around with - `request({url: 'http://visual-recognition-demo.mybluemix.net/images/horses.jpg', encoding: null})` – Justin Maat Mar 31 '15 at 19:30
  • @GermanAttanasioRuiz Np, follow me on github if you'd like. Will be putting alot of good examples of Node code continually throughout the year :) – Justin Maat Mar 31 '15 at 20:18
  • Thank you! I was providing a callback and was hitting the 500MB string size limit in node. Adding `encoding:null` solved my problem – Zayin Krige Feb 24 '20 at 06:59