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