I'm new to promises and writing network code using requests and promises in NodeJS.
I would like to remove these nested promises and chain them instead, but I'm not sure how I'd go about it/whether it is the right way to go.
exports.viewFile = function(req, res) {
var fileId = req.params.id;
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
boxViewerRequest('documents', {url: response.request.href}, 'POST')
.then(function(response) {
boxViewerRequest('sessions', {document_id: response.body.id}, 'POST')
.then(function(response) {
console.log(response);
});
});
});
};
This is the request code:
var baseContentURL = 'https://api.box.com/2.0/';
var baseViewerURL = 'https://view-api.box.com/1/';
function boxContentRequest(url, accessToken) {
return new Promise(function (resolve, reject) {
var options = {
url: baseContentURL + url,
headers: {
Authorization: 'Bearer ' + accessToken,
}
};
request(options, function (err, res) {
if (err) {
return reject(err);
} else if (res.statusCode !== 200) {
err = new Error("Unexpected status code: " + res.statusCode);
err.res = res;
return reject(err);
}
resolve(res);
});
});
}
function boxViewerRequest(url, body, method) {
return new Promise(function (resolve, reject) {
var options = {
method: method,
url: baseViewerURL + url,
headers: {
Authorization: 'Token ' + config.box.viewerApiKey
},
json: body
};
request(options, function (err, res, body) {
if (err) {
return reject(err);
} else if (res.statusCode !== 200 && res.statusCode !== 201 && res.statusCode !== 202) {
err = new Error("Unexpected status code: " + res.statusCode);
err.res = res;
return reject(err);
}
resolve(res, body);
});
});
}
Any insight would be appreciated.
From every then callback, you will need to return the new promise:
exports.viewFile = function(req, res) {
var fileId = req.params.id;
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequest('documents', {url: response.request.href}, 'POST');
})
.then(function(response) {
return boxViewerRequest('sessions', {document_id: response.body.id}, 'POST');
})
.then(function(response) {
console.log(response);
});
};
The promise that is returned by the .then() call will then resolve with the value from the "inner" promise, so that you easily can chain them.
Generic pattern:
somePromise.then(function(r1) {
return nextPromise.then(function(r2) {
return anyValue;
});
}) // resolves with anyValue
||
\||/
\/
somePromise.then(function(r1) {
return nextPromise;
}).then(function(r2) {
return anyValue;
}) // resolves with anyValue as well
Promise.prototype.then is designed to return another promise, so that you can chain them.
The handler function passed to .then() can return a normal value, like a number or string or object, and this value will get passed on to the next handler of .then().
One option is to have boxViewerRequestSync be a synchronous function that returns a response object:
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequestSync('documents', {url: response.request.href}, 'POST')
})
.then(function(response) { // this `response` is returned by `boxViewerRequestSync`
return boxViewerRequestSync('sessions', {document_id: response.body.id}, 'POST')
})
.then(function(response) {
console.log(response);
})
But of course your boxViewerRequest is asynchronous and returns a promise instead. In that case, the handler function passed to .then() could also return a completely unrelated Promise. This new promise is executed synchronously, and once it is resolved/rejected, its result is passed on to the next handler.
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequest('documents', {url: response.request.href}, 'POST')
})
.then(function(response) { // this `response` is the result of resolving the promise returned by `boxViewerRequest`
return boxViewerRequest('sessions', {document_id: response.body.id}, 'POST')
})
.then(function(response) {
console.log(response);
})
Keeping track of all the promises is confusing, but the bottom line is this: Promise.prototype.then will always return a Promise object, but the handler function passed to Promise.prototype.then can return anything, even undefined, or even another Promise. Then that value, or the value of the resolved Promise, is passed to the next handler function.
Related
I have a NodeJS application and I think I have an issue with returning from inside a nested Promise.
As below, the getToken function is working. It calls another function to retrieve a password. After this, it uses the password value when making a GET call.
We then successfully get a token and we print the body to the console. This works.
However, I now have the challenge of passing the value of body which is my token, to another method for later consumption. printBodyValue currently fails and fails with an 'undefined' error.
How can I pass the value from deep inside getToken to printBodyValue
getToken: function() {
module.exports.readCredentialPassword()
.then(result => {
var request = require('request-promise');
var passwd = result;
var basicAuthData = "Basic " + (new Buffer("fooUser" + ":" + passwd).toString("base64"));
var options = {
method: "GET",
uri: ("http://localhost:8001/service/verify"),
followRedirects: true,
headers: {
"Authorization": basicAuthData
}
};
return request(options)
.then(function (body) {
console.log("Token value is: ", body);
return body;
})
.catch(function (err) {
console.log("Oops! ", err);
});
});
}
printBodyValue: function() {
module.exports.getToken().then(function(body) {
console.log("Token value from printBodyValue is: \n", body);
});
}
In getToken, instead of using the nested promise anti-pattern, chain your promises instead, and return the final promise, so that you can then consume the promise and use its resolved value:
(also, since you're using ES6, prefer const over var)
getToken: function() {
return module.exports.readCredentialPassword()
.then(result => {
const request = require('request-promise');
const passwd = result;
const basicAuthData = "Basic " + (new Buffer("fooUser" + ":" + passwd).toString("base64"));
module.exports.log("Sending Request: ", jenkinsCrumbURL);
const options = {
method: "GET",
uri: ("http://localhost:8001/service/verify"),
followRedirects: true,
headers: {
"Authorization": basicAuthData
}
};
return request(options);
})
.then(function(body) {
console.log("Token value is: ", body);
// the return value below
// will be the final result of the resolution of
// `module.exports.readCredentialPassword`, barring errors:
return body;
})
.catch(function(err) {
console.log("Oops! ", err);
});
}
printBodyValue: function() {
module.exports.getToken().then(function(body) {
console.log("Token value from printBodyValue is: \n", body);
});
}
I am trying to check on an API if a picture It is valid. I am doing it with promises, I want that if a check on API return me a failure, stop execute de promise and call a fuction.
Heres my code.
My function to call the promises
checkPhotos(options,formData, "front", res, false).then(function(response) {
if(response!== 'error'){
options.url = 'http://'+config.verifier_host+':'+config.verifier_port+config.verifier_endpoint_sc;
readImage = fs.createReadStream("tmp/"+imgOne+".jpeg");
formData = {
uuid : request.uuid,
document_type : 1, //req.body.document_type
analysis_type : 1,
document_image: {
value: readImage,
options: {
filename: 'tmp/'+imgOne+'.jpeg',
contentType: null
}
}
};
console.log("2a Ejecución")
return checkPhotos(options,formData, "back", res, false);
}else {
return;
}
}).then(function(response) {
if(response!== 'error'){
options.url = 'http://'+config.verifier_host+':'+config.verifier_port+config.verifier_endpoint_sc;
readImage = fs.createReadStream("tmp/"+nombreImagenBackimg2+".jpeg");
formData = {
uuid : request.uuid,
document_type : 1, //req.body.document_type
analysis_type : 2,
document_image: {
value: readImage,
options: {
filename: 'tmp/'+img2+'.jpeg',
contentType: null
}
}
};
console.log("3a Ejecución")
return checkPhotos(options,formData, "back", res, false);
}else {
return;
}
}).then(function(response) {
if(response!== 'error'){
readImage = fs.createReadStream("tmp/"+nombreImagenSelfieimg3+".jpeg");
formData = {
uuid : request.uuid,
selfie_image: {
value: readImage,
options: {
filename: 'tmp/'+img3+'.jpeg',
contentType: null
}
}
};
options.url = 'http://'+config.verifier_host+':'+config.verifier_port+config.verifier_endpoint_tc;
console.log("4a y última ejecución")
return checkPhotos(options, formData, null, res, true, request);
}else {
return;
}
}).catch(function(err) {
logger.error('PID ' + process.pid + ' Error response' + err.message);
console.log("Catch -> "+ err.message);
});
My function promise.
function checkPhotos (options, formData, positionPhoto, res, bandera, request) {
var promise = new Promise(function (resolve, reject) {
var post_req = requests.post({headers: {Authorization : options.headers.authorization}, url:options.url, formData: formData}, function (err, httpResponse, body) {
if (err) {
logger.error(' PID ' + process.pid + err);
return console.error('Error:', err);
}
if(!body){
logger.error(' PID ' + process.pid + formData.document_image.options.filename);
return false;
}
responseBody = JSON.parse(body);
if(bandera){
if(responseBody.success === 'error'){
resolve(responseBody.success);
return getData(null, res, responseBody);
}else {
resolve(formData);
getData(null, res);
}
}else {
if(responseBody.success === 'error'){
logger.error(' PID ' + process.pid + responseBody);
resolve(responseBody.success);
return getData(null, res, responseBody);
}else {
resolve(formData);
console.log("Success")
}
}
});
});
return promise;
}
Call reject on error instead of resolve. This way the promise chain is immediately rejected and any subsequent calls to .then are not run.
If you want to stop the promise chain from inside a .then call, you can return a Promise.reject(…) value OR throw an error.
Example:
const promise = checkPhotos(...);
promise
.then(askApi)
.then((response) => { throw response.body; })
.then(willNotBeExecuted)
.catch(thisWillbeExecutedAfterThrow);
function checkPhotos (options, formData, positionPhoto, res, bandera, request) {
return (resolve, reject) => {
// … make request
if (!bandera) { reject(getData); }
};
}
I'm trying to invoke a REST call and return a promise so I can manipulate the data afterwhich.
var self = this;
var returnPromise;
returnPromise = self.httpService.testService();
returnPromise.then(function(result){
console.log(result);
});
My REST service is located in another file which has the following:
testService() {
console.log("start of testService");
var request = require('request');
var user = "test";
var ipadd = "127.0.0.1";
request({
url: 'https://' + 'LocalHost' + '/URLOFWEBSERVICE',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
userID: user,
userIpAddress: ipadd
}
}, function(error, response, body) {
if (error) {
console.log(error);
} else {
console.log(response.statusCode, body);
var newPro = new Promise(function(fulfill, reject) {
fulfill(body);
});
console.log(newPro);
return newPro;
}
});
}
I'm able to print out response.stateCode , body( REST result) and the "invoked fulfill" console is printed out.
The problem lies with the
returnPromise.then
in the first page, in which ".then" returns me undefined.
At first I thought that it might be the promise has been called before the REST returns me a response. So, I thought of doing a timeout function to test.
setTimeout(
function(){
console.log(returnPromise);
}
, 5000);
But even so, returnPromise returns me "undefined".
If you expect a function to return a promise, it should return a promise
your testService does not return anything
this does:
testService() {
console.log("start of testService");
var request = require('request');
var user = "test";
var ipadd = "127.0.0.1";
return new Promise(function(fulfill, reject) {
request({
url: 'https://' + 'LocalHost' + '/URLOFWEBSERVICE',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
userID: user,
userIpAddress: ipadd
}
}, function(error, response, body) {
if (error) {
// reject the promise, handle with .catch
reject(error);
} else {
console.log(response.statusCode, body);
fulfill(body);
}
});
});
}
That can be called as
// var self = this; // why? not needed in the code shown
// var returnPromise; // why? it's not needed in the code shown
this.httpService.testService()
.then(function(result) {
console.log(result);
})
.catch(function(err) {
// handle your errors here
});
I am using Bluebird library with NodeJS (with SailsJS framework)
Promise.all() is not capturing the event when all the promises in promises array are resolved.
What changes should be made in order to solve this problem?
var Promise = require("bluebird");
var request = require('request');
var http = require('http');
function searchMultiple(titles) {
var results = [];
return new Promise( function( resolveGlobal, rejectGlobal ){
var url = "http://xxx.xxx";
var promises = [];
titles.forEach(function (title, index) {
promises[index] = new Promise( function (resolve, reject) {
var data = {"x":title};
request({
uri: url,
method: "POST",
body : data
}, function(error, response, body) {
return resolve(body)
}
}
},
function (error, response, body) {
console.log("error");
return resolve();
}
);
})
})
Promise.all(promises).then(function(combinedResults) {
console.log("successfully resolved all promises");
return resolveGlobal(combinedResults);
}).catch(function (reason) {
console.log("error");
return rejectGlobal();
});
})
}
There is no need for you to return resolve(value), as it should only resolve the with the given result value.
There's also no reason to create a new promise in your searchMultiple function, since the Promise.all returns a promise. You should just return the promise you already have!
The resolveGlobal() is thus unnecessary and you can just return the result instead, since the then will wrap it as a resolved value.
All of your code can be rewritten as two very simple functions
function searchMultiple(titles) {
//Empty array of promises
var promises = [];
var url = "http://xxx.xxx";
//Get a promise for each title and push to array
titles.forEach(function(title){
promises.push(getData(title, url));
});
//Wait for all promises to resolve, and return the result
return Promise.all(promises)
.then(function(arrayOfResults){
//If this only shall return the array, this can be omitted aswell as the catch!
return arrayOfresults;
})
.catch(function(reason){
//Handle errors
});
}
function getData(title, url){
return new Promise(function(resolve, reject){
var data = {"x":title};
request({
uri: url,
method: "POST",
body : data
}, function(error, response, body) {
resolve(body)
}
}
},
function (error, response, body) {
console.log("error");
//Consider rejecting here instead since you'll get a result that is 'undefined'
resolve();
});
});
}
You should consider rejecting the promise in the error handler instead of resolving it with an undefined value. You might end up with errors further down the road if you get a result array back that have values that are undefined.
Try this:
var Promise = require('bluebird');
var request = require('request');
function searchMultiple(titles) {
return new Promise(function (resolveGlobal, rejectGlobal) {
var url = 'http://xxx.xxx';
var promises = [];
titles.forEach(function (title) {
promises
.push(new Promise(function (resolve, reject) {
var data = {
'x': title
};
request({
uri: url,
method: 'POST',
body: data
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
return resolve(body);
}
return reject(error);
});
}));
});
Promise
.all(promises)
.then(function (combinedResults) {
console.log('successfully resolved all promises');
return resolveGlobal(combinedResults);
})
.catch(function (error) {
console.log('error');
return rejectGlobal(error);
});
});
}
And call function:
searchMultiple([...])
.then(function (results) {
console.log(results);
})
.catch(function (error) {
console.log(error);
});
I'm new to promises and writing network code using requests and promises in NodeJS.
I would like to remove these nested promises and chain them instead, but I'm not sure how I'd go about it/whether it is the right way to go.
exports.viewFile = function(req, res) {
var fileId = req.params.id;
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
boxViewerRequest('documents', {url: response.request.href}, 'POST')
.then(function(response) {
boxViewerRequest('sessions', {document_id: response.body.id}, 'POST')
.then(function(response) {
console.log(response);
});
});
});
};
This is the request code:
var baseContentURL = 'https://api.box.com/2.0/';
var baseViewerURL = 'https://view-api.box.com/1/';
function boxContentRequest(url, accessToken) {
return new Promise(function (resolve, reject) {
var options = {
url: baseContentURL + url,
headers: {
Authorization: 'Bearer ' + accessToken,
}
};
request(options, function (err, res) {
if (err) {
return reject(err);
} else if (res.statusCode !== 200) {
err = new Error("Unexpected status code: " + res.statusCode);
err.res = res;
return reject(err);
}
resolve(res);
});
});
}
function boxViewerRequest(url, body, method) {
return new Promise(function (resolve, reject) {
var options = {
method: method,
url: baseViewerURL + url,
headers: {
Authorization: 'Token ' + config.box.viewerApiKey
},
json: body
};
request(options, function (err, res, body) {
if (err) {
return reject(err);
} else if (res.statusCode !== 200 && res.statusCode !== 201 && res.statusCode !== 202) {
err = new Error("Unexpected status code: " + res.statusCode);
err.res = res;
return reject(err);
}
resolve(res, body);
});
});
}
Any insight would be appreciated.
From every then callback, you will need to return the new promise:
exports.viewFile = function(req, res) {
var fileId = req.params.id;
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequest('documents', {url: response.request.href}, 'POST');
})
.then(function(response) {
return boxViewerRequest('sessions', {document_id: response.body.id}, 'POST');
})
.then(function(response) {
console.log(response);
});
};
The promise that is returned by the .then() call will then resolve with the value from the "inner" promise, so that you easily can chain them.
Generic pattern:
somePromise.then(function(r1) {
return nextPromise.then(function(r2) {
return anyValue;
});
}) // resolves with anyValue
||
\||/
\/
somePromise.then(function(r1) {
return nextPromise;
}).then(function(r2) {
return anyValue;
}) // resolves with anyValue as well
Promise.prototype.then is designed to return another promise, so that you can chain them.
The handler function passed to .then() can return a normal value, like a number or string or object, and this value will get passed on to the next handler of .then().
One option is to have boxViewerRequestSync be a synchronous function that returns a response object:
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequestSync('documents', {url: response.request.href}, 'POST')
})
.then(function(response) { // this `response` is returned by `boxViewerRequestSync`
return boxViewerRequestSync('sessions', {document_id: response.body.id}, 'POST')
})
.then(function(response) {
console.log(response);
})
But of course your boxViewerRequest is asynchronous and returns a promise instead. In that case, the handler function passed to .then() could also return a completely unrelated Promise. This new promise is executed synchronously, and once it is resolved/rejected, its result is passed on to the next handler.
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequest('documents', {url: response.request.href}, 'POST')
})
.then(function(response) { // this `response` is the result of resolving the promise returned by `boxViewerRequest`
return boxViewerRequest('sessions', {document_id: response.body.id}, 'POST')
})
.then(function(response) {
console.log(response);
})
Keeping track of all the promises is confusing, but the bottom line is this: Promise.prototype.then will always return a Promise object, but the handler function passed to Promise.prototype.then can return anything, even undefined, or even another Promise. Then that value, or the value of the resolved Promise, is passed to the next handler function.