Return Promise From REST Call - javascript

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

Related

parse2 upgrade javascript promise question

I have the following old parse2 code that I need to upgrade to parse4. I have the following snippet of original code: EDIT: realized it was using old request (requestLib). I have replaced that with axios and now am showing my changes::
var query = new Parse.Query(request.params.documentType);
query.equalTo('objectId', request.params.documentObjectId);
return query.first({ useMasterKey: true })
.then(function (result) {
if (!result) { return Promise.error('Sorry, this document is not available to be sent.'); }
documentObject = result;
return result
})
.then(function(result){
if (useNewHTMLEmail) {
if (p.type === undefined) {
return console.log("type property must be defined for HTML template")
}
return Parse.Cloud.run("getEmail", {documentId: request.params.documentObjectId, type: p.type, text: baseMessage, documentType: p.documentType, customFields: p.customFields })
.then(function(result) {
baseMessage = result;
return true;
})
}
else {
return Promise.resolve();
}
})
.then(function (result) {
if (p.appendPDF == true && documentObject.get('pdf') !== undefined) {
var download = function (uri, filename, callback) {
requestLib.head(uri, function (err, res, body) {
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
requestLib(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
var url = documentObject.get('pdf').url();
var parts = url.split("/");
var lastSegment = parts.pop() || parts.pop();
var promise = new Parse.Promise();
download(url, lastSegment, function () {
file = fs.readFileSync(lastSegment);
promise.resolve(result);
});
return promise;
}
else {
return Promise.resolve(result);
}
})
So far I have made the following changes:
var query = new Parse.Query(request.params.documentType);
query.equalTo('objectId', request.params.documentObjectId);
documentObject = await query.first({ useMasterKey: true });
if (documentObject === undefined){
throw new Error("Bad document in sendMail");
}
if (useNewHTMLEmail) {
if (p.type === undefined) {
throw new Error("type property must be defined for HTML template")
}
baseMessage = await Parse.Cloud.run("getEmail", {documentId: request.params.documentObjectId, type: p.type, text: baseMessage, documentType: p.documentType, customFields: p.customFields })
}
The next section is where I get confused using callbacks and async await. Here is my attempt with Axios:
var url = documentObject.get('pdf').url();
var parts = url.split("/");
var lastSegment = parts.pop() || parts.pop();
axios({
method: 'get',
url: url,
responseType:'stream'
})
.then(res => {
res.data.pipe(fs.createWriteStream(lastSegment));
})
.catch(err => console.log(err));
How do I translate this portion now:
var promise = new Parse.Promise();
download(url, lastSegment, function () {
file = fs.readFileSync(lastSegment);
promise.resolve(result);
});
EDIT: Why doesn't this pass through:
var writeStream = fs.createWriteStream(lastSegment);
await new Promise(async (resolve) => {
const response = await axios({
method: "GET",
url: url,
responseType: "stream"
});
response.data.pipe(writeStream);
writeStream.on('error', function (err) {
console.log(err);
});
});
file = fs.readFileSync(lastSegment); <=== never gets executed.
Thanks
What do I replace Promise.resolve() with?
Nothing. The return Promise.resolve() does nothing in a then callback, in fact it could have been omitted even there.
Or, the "return promise"?
You'll need to construct and await a new Promise for the download. But you'd probably want to modernise that function as well, getting rid of the readFileSync and altogether replacing requestLib with something that returns a promise instead of a stream.
This worked:
var writeStream = fs.createWriteStream(lastSegment);
console.log("start axios");
const response = await axios({
method: "GET",
url: url,
responseType: "stream"
});
response.data.pipe(writeStream);
writeStream.on('error', function (err) {
console.log(err);
});
file = fs.readFileSync(lastSegment);

JS Functions to make an API call

I have the following code.
I'm trying to make an API call (retrieve) passing since (obj.since), therefore, every time I make the call the API does not retrieve all data. However, so far, I haven't found the way to get since from the last record on my database.
var express = require("express");
var article = require("../models/article");
var request = require('request');
article.findOne({}, {since:1, _id:0}, { sort: { 'since' : -1 } }, function (err,obj) {
var **dataString** = `'{"consumer_key":"XXXXX", "access_token":"XXXXXXX", "since":"${obj.since}"}'`;
});
var options = {
url: 'https://xxxxxxxxx.com/v3/get',
method: 'POST',
headers: headers,
body: **dataString**
}
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
let package = JSON.parse(body);
for(var attributename in package.list){
var title = package.list[attributename]["given_title"] ;
var url = package.list[attributename]["given_url"] ;
var newArticle = {title: title, url: url, since: since}
article.create(newArticle, function(error, newlyCreated){
if(error){
console.log(error);
} else {
console.log(newlyCreated);
}
});
}
}
else {
console.log(error);
}
};;
request(options,callback)
How can I make an API call getting the obj.since from the database (MongoDB) and pass it to an object (options)?
You are doing async callback style operation in for loop which is causing this issue. I will change few things
Change findOne to have exec at the end so it returns promise
article.create already returns a promise if no callback specified.
Convert request to a promise style.
Use for..of loop to do async operation.
The code will look like this
var express = require("express");
var article = require("../models/article");
var request = require('request');
function hitApi(dataString) {
return new Promise((resolve, reject) => {
var options = {
url: 'https://xxxxxxxxx.com/v3/get',
method: 'POST',
headers: headers,
body: dataString
}
request(options, error, response, body => {
if (err) {
reject(err);
}
resolve(body);
});
});
}
async function perform() {
const dataString = await article.findOne({}, {since:1, _id:0}, { sort: { 'since' : -1 } }).exec();
const response = await hitApi(dataString);
const package = JSON.parse(response.body);
for (const attributename of package.list) {
var title = package.list[attributename]["given_title"] ;
var url = package.list[attributename]["given_url"] ;
var newArticle = {title: title, url: url, since: since}
const newlyCreated = await article.create(newArticle);
console.log(newlyCreated);
}
}
You can then call perform function. There might be few syntax error but you will get an idea.

Returning nested promises to another function

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

How to capture the event in which all promises in the array are resolved?

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

Calling async functions recursively

I need to have an async method eg. getWeather called forever with a small delay between the success of previous call and beginning of the next call. I have used a recursive function for the purpose. I am concerned if this can cause a performance hit. Are there any better ways to do this?
var request = require('request');
var Promise = require('bluebird');
var delayTwoSecs = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 2000);
});
};
var getWeather = function() {
return new Promise(function(resolve, reject) {
request({
method: 'GET',
uri: 'http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139'
}, function(error, response, body) {
if (error) {
reject(error);
} else {
resolve(body)
}
});
});
};
var loopFetching = function() {
getWeather()
.then(function(response) {
console.log(response);
return delayTwoSecs();
}).then(function(response) {
loopFetching();
});
};
loopFetching();
You don't need the delayTwoSecs function, you can use the Promise.delay function.
Instead of getWeather, you can use the bluebird to Promisify all the functions and use the proper function, in this case getAsync, directly.
So, your program becomes like this
var Promise = require('bluebird');
var request = Promise.promisifyAll(require('request'));
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139';
(function loopFetching() {
request.getAsync(url)
// We get the first element from the response array with `.get(0)`
.get(0)
// and the `body` property with `.get("body")`
.get("body")
.then(console.log.bind(console))
.delay(2000)
.then(loopFetching)
.catch(console.err.bind(console));
})();
This is called Immediately Invoking Function Expression.
setInterval() for recurring requests
You're over-complicating it with nested calls. Use setInterval() instead.
var request = require('request');
var Promise = require('bluebird');
var getWeather = function() {
return new Promise(function(resolve, reject) {
request({
method: 'GET',
uri: 'http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139'
}, function(error, response, body) {
if (error) {
reject(error);
} else {
resolve(body)
}
});
});
};
var my_interval = setInterval("getWeather()",2000);

Categories

Resources