0

Today I am doing this request to Linode API.

var options = {
    hostname: 'api.linode.com',
    path: '',
    port: 443,
    method: 'GET'
}

var req = https.request(options, function(response) {
    response.setEncoding('utf8');
    response.on('data', function(d) {
        body = JSON.parse(d.toString());
    });

    response.on('end', function() {
        console.log(body);
    });
}).end();

The output is working as expected on this example.

However, I need to put the response into a variable, and not log it to console.

var body = '';
var req = https.request(options, function(response) {
    response.setEncoding('utf8');
    response.on('data', function(d) {
        body = JSON.parse(d.toString());
    });
}).end();
console.log(body);
return body;

Running the above code, the answer is always empty, since looks like the console.log() function or return clause are not waiting for end of the request.

I resolved the problem using the setTimeout( function() { console.log(body); }, 2000 ) function, but to be honest can't see it as an effective solution, since the timeout will be different on each request.

Other solution I tried was while (!req.finished) {} console.log(body);, but it is not working as expected too.

Finally, I tried to add this:

response.on('end', function() {
    return body;
});

But no success as well :(

That said, do you have any suggestions to make this function wait for request timeout before return the value of the body variable?

  • Return a promise, `then` do something when it fulfills. –  Dec 05 '14 at 02:37
  • @torazaburo Do you have any examples? Sorry, I got the idea, but can't see how to make it happen. Thanks! – Tiago Hillebrandt Dec 05 '14 at 02:42
  • There are about a dozen or more questions on SO on this very topic. Search for them. For example, see http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call. –  Dec 05 '14 at 02:56
  • @torazaburo The questions I found there are to do it via AJAX, and not via Node.js using https module. However, the below answer worked as expected. Thanks for the help – Tiago Hillebrandt Dec 05 '14 at 03:11
  • Glad to hear that. The two are conceptually identical. The "modern" way to do this is with promises. –  Dec 05 '14 at 03:19

1 Answers1

3

The simplest way is to put the code in a function that takes in (at least) a callback. You'll also want to buffer data from all data events since you cannot assume there will be only one. Example:

// you may want to add other parameters too depending on your needs of course ...
function linodeReq(cb) {
  var options = {
    hostname: 'api.linode.com',
    path: '',
    port: 443,
    method: 'GET'
  }

  https.get(options, function(response) {
    var buffer = '';
    response.on('data', function(d) {
      buffer += d;
    }).on('end', function() {
      var body;
      try {
        body = JSON.parse(buffer)
      } catch (err) {
        return cb(err);
      }
      cb(null, body);
    }).setEncoding('utf8');
  });
}

// then use it like ...

linodeReq(function(err, result) {
  // check for `err` first ...
});

You should also handle the error events on the request (and response) object too, passing them to the callback if they occur. This could happen for example if the hostname couldn't be resolved or some other connection error.

mscdex
  • 104,356
  • 15
  • 192
  • 153