web-dev-qa-db-fra.com

Node.JS Attendre le rappel de REST Service qui fait une requête HTTP

J'utilise un module express pour créer une API Restful dans Node.JS. Dans mon service, je fais des demandes http supplémentaires à des points de terminaison externes (côté serveur) et je dois renvoyer les données de ces demandes http à mon corps de demande de service Web.

J'ai confirmé que si j'utilise console.log sur toutes les actions que mène le Web Service, j'obtiens les données dont j'ai besoin. Cependant, lorsque j'essaie de renvoyer ces valeurs au service, elles reviennent Null. Je sais que cela est dû à l'async et que le rappel n'attend pas la fin de la demande http.

Existe-t-il un moyen de faire fonctionner cela?

38
Rob

Une pratique courante consiste à utiliser le module async .

npm install async

Le module async possède des primitives pour gérer diverses formes d'événements asynchrones.

Dans votre cas, le async#parallel l'appel vous permettra de faire des demandes à toutes les API externes en même temps, puis de combiner les résultats pour les retourner à votre demandeur.

Puisque vous faites des requêtes http externes, vous trouverez probablement le module request également utile.

npm install request

Utilisation de request et async#parallel votre gestionnaire d'itinéraire devrait ressembler à ceci ...

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]});
  }
  );
};

Vous pouvez également lire d'autres méthodes de séquencement de rappel ici .

42
Daniel

Node.js est tout au sujet des rappels. À moins que l'appel d'API ne soit synchrone (rare et ne devrait pas être fait), vous ne renvoyez jamais de valeurs de ces appels, mais rappelez-le avec le résultat à l'intérieur de la méthode de rappel, ou appelez la méthode express res.send

Request.js est une excellente bibliothèque pour invoquer des requêtes Web.

Prenons l'exemple très simple d'appeler google. En utilisant res.send, votre code express.js pourrait ressembler à:

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);
    }
  })
});

Vous pouvez également transmettre un rappel à la méthode qui appelle la demande Web et appeler ce rappel à partir de cette méthode:

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

Autres exemples de réponses utilisant wait.for:

Exemple tiré de la réponse de Daniel (async), mais en utilisant 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