web-dev-qa-db-ja.com

Node.JS REST HTTPリクエストを行うサービスのコールバックを待つ

Expressモジュールを使用して、Node.JS内でRestful APIを作成しています。私のサービスでは、外部のエンドポイント(サーバー側)に追加のHTTPリクエストを作成しています。これらのHTTPリクエストからのデータをWebサービスリクエスト本文に返す必要があります。

Webサービスが実行しているすべてのアクションでconsole.logを使用すると、必要なデータを取得できることを確認しました。ただし、これらの値をサービスに返そうとすると、Nullが返されます。これは非同期が原因であり、コールバックがhttp要求の終了を待機していないことがわかっています。

この作品を作る方法はありますか?

38
Rob

一般的な方法は、 async モジュールを使用することです。

npm install async

asyncモジュールには、さまざまな形式の非同期イベントを処理するプリミティブがあります。

あなたの場合、async#parallel呼び出しにより、すべての外部APIに同時に要求を行い、結果を結合して要求者に返すことができます。

外部のHTTPリクエストを作成しているので、おそらく request モジュールも役立つでしょう。

npm install request

requestasync#parallelを使用すると、ルートハンドラは次のようになります。

var request = require('request');
var async = require('async');

exports.handler = function(req, res) {
  async.parallel([
    /*
     * First external endpoint
     */
    function(callback) {
      var url = "http://external1.com/api/some_endpoint";
      request(url, function(err, response, body) {
        // JSON body
        if(err) { console.log(err); callback(true); return; }
        obj = JSON.parse(body);
        callback(false, obj);
      });
    },
    /*
     * Second external endpoint
     */
    function(callback) {
      var url = "http://external2.com/api/some_endpoint";
      request(url, function(err, response, body) {
        // JSON body
        if(err) { console.log(err); callback(true); return; }
        obj = JSON.parse(body);
        callback(false, obj);
      });
    },
  ],
  /*
   * Collate results
   */
  function(err, results) {
    if(err) { console.log(err); res.send(500,"Server Error"); return; }
    res.send({api1:results[0], api2:results[1]});
  }
  );
};

他のコールバックシーケンスメソッドについても読むことができます here

42
Daniel

Node.jsはコールバックに関するものです。 API呼び出しが同期的でない場合(まれに実行されるべきではありません)、それらの呼び出しから値を返すことはありませんが、コールバックメソッド内からの結果でコールバックするか、expressメソッドres.sendを呼び出します

Webリクエストを呼び出すための優れたライブラリはrequest.jsです

Googleを呼び出す実際の簡単な例を見てみましょう。 res.sendを使用すると、express.jsコードは次のようになります。

var request = require('request');
app.get('/callGoogle', function(req, res){
  request('http://www.google.com', function (error, response, body) {
    if (!error && response.statusCode == 200) {
      // from within the callback, write data to response, essentially returning it.
      res.send(body);
    }
  })
});

または、Web要求を呼び出すメソッドにコールバックを渡し、そのメソッド内からそのコールバックを呼び出すことができます。

app.get('/callGoogle', function(req, res){
  invokeAndProcessGoogleResponse(function(err, result){
    if(err){
      res.send(500, { error: 'something blew up' });
    } else {
      res.send(result);
    }
  });
});

var invokeAndProcessGoogleResponse = function(callback){
  request('http://www.google.com', function (error, response, body) {

    if (!error && response.statusCode == 200) {
      status = "succeeded";
      callback(null, {status : status});
    } else {
      callback(error);
    }
  })
}
17
Oved D

Wait.for https://github.com/luciotato/waitfor

Wait.forを使用した他の回答の例:

Daniel's Answer(async)の例ですが、Wait.forを使用しています

var request = require('request');
var wait = require('wait.for');

exports.handler = function(req, res) {
try {  
    //execute parallel, 2 endpoints, wait for results
    var result = wait.parallel.map(["http://external1.com/api/some_endpoint"
                 ,"http://external2.com/api/some_endpoint"]
                 , request.standardGetJSON); 
    //return result
    res.send(result);
}
catch(err){
    console.log(err); 
    res.end(500,"Server Error")
}
};

//wait.for requires standard callbacks(err,data)
//standardized request.get: 
request.standardGetJSON = function ( options, callback) {
    request.get(options,
            function (error, response, body) {
                //standardized callback
                var data;
                if (!error) data={ response: response, obj:JSON.parse(body)};
                callback(error,data);
            });
}
3
Lucio M. Tato