How can I use the value of the body outside this method? - node.js

var request = require('request');
var boardsCall = {
method: 'GET',
url: 'https://api.trello.com/1/organizations/xxxxxxxxxx/boards?filter=open&fields=id,name',
qs: {
key: 'xxxxxxxxxxxxxxxx',
token: 'xxxxxxxxxxxxxxxxxxxxxxxxx'
}
};
function test(url, callback) {
request(url, function(error, response, body) {
if (error) {
return callback(error);
}
callback(null, JSON.parse(body));
})
}
const x = test(boardsCall, function(err, body) {
if (err) {
console.log(err);
}
else {
return body;
}
})
console.log(x);
how can I use the value of the body outside?
to use it in other methods later
I am open to any changes best practices, I read a lot and got a bit confused on the topic of callbacks, promises async await.

In my approach request is wrapped with Promise, test function returns Promise response. Inside the main method test function will be executed synchronously. Once the response value assigned to x do remaining processing logic inside the main() method.
var request = require('request');
var boardsCall = {
method: 'GET',
url: 'https://api.trello.com/1/organizations/xxxxxxxxxx/boards?filter=open&fields=id,name',
qs: {
key: 'xxxxxxxxxxxxxxxx',
token: 'xxxxxxxxxxxxxxxxxxxxxxxxx'
}
};
function test(url) {
//Wrapping request callback with Promise
return new Promise((res, rej)=> {
request(url, function(error, response, body) {
if (error) {
rej(error);
}
res(JSON.parse(body));
})
})
}
async function main() {
try {
const x = await test(boardsCall);
console.log("Result : ", x );
// Remaining logic to process based on x value
} catch(e) {
console.error("Error :", e);
}
}
//Calling main method
main()

Related

how to get data outside request

I have a scenario where i need to take response (body) of request method outside request. How can i do it?
request.post({
url: 'http://localhost/api/messages',
form: { key: message }
}, function (err, httpResponse, body) {
tmsg = body;
})
console.log(tmsg);
I need this tmsg outside for next processing, Actual scenario is as below.
app.post('/incomemsg', function (req, res) {
var mediaCount = req.body.NumMedia;
if (mediaCount == 0) {
//var twiml = getResponse(message);
var twiml = new MessagingResponse();
request.post({
url: 'http://localhost:3978/api/messages',
form: { key: message }
}, function (err, httpResponse, body) {
tmsg = body;
})
console.log(tmsg);
}else {
//dosomething which outputs tmsg
}
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(tmsg.toString());
});
The problem is you are trying to assign value to a global variable in request.post's callback() which is only called after request.post is executed by Asynchronous logic(API calls are all async), so a better way would be to promisify request.post and await the request.post to make it seem synchronous.
const requestPromisified = requestObject =>
new Promise((resolve, reject) => {
request.post(requestObject, function(err, httpResponse, body) {
if (err) {
reject(err);
}
resolve(body);
});
});
const body = await requestPromisified({
method: "POST",
url: "http://localhost/api/messages",
form: { key: message }
});
You only can do something with tmsg when you made the request so you need to rearrange your code like this:
app.post('/incomemsg', function (req, res) {
var mediaCount = req.body.NumMedia;
var twiml = new MessagingResponse();
request.post({
url: 'http://localhost:3978/api/messages',
form: { key: message }
}, function (err, httpResponse, body) {
tmsg = body;
console.log(tmsg);
if (mediaCount === 0) {
//do something with tmsg
} else {
//do something else with tmsg
}
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(tmsg.toString());
});
});
Otherwise tmsg will be null because there was no request made to fill that variable.

How to return a string from a node js api call

I have using a code snippet which will return a value after post rest call to an api.
But where ever i am calling the function its not returning the value and prints undefined.
when ever i will call any where getAccessToken(), its says undefiuned, but ifi print the value am getting the output.
How do the called will get the return value, do i need to change anything in the below code.
Thanks
var getAccessToken = exports.getAccessToken = function (res) {
// body...
const request = require('request');
const authKey='EAcEa4o4SkBLo9IpZpW4Y7oDn7d6b30GlouNh28pJ6Q='
const ContentType='application/x-www-form-urlencoded' ;
var postData={
'grant_type':'client_credentials'
};
const options = {
url: 'https://xyz/v1/login',
method: 'POST',
headers: {
'Content-Type': ContentType,
'Authorization':authKey
},
body:require('querystring').stringify(postData)
};
var token;
request(options, function(errror, response, body) {
//console.log(JSON.parse(body));
token= JSON.parse(body).access_token;
});
return token;
}
Your function doesn't return anything. You may use async/await, promises or callbacks to fix it.
exports.getAccessToken = async (res) => {
...
return await request(...)
}
OR
exports.getAccessToken = function(res) {
...
return new Promise(function(resolve, reject) {
...
request(options, function(errror, response, body) {
var token = JSON.parse(body).access_token;
resolve(token);
}
});
}
// Use it like
getAccessToken().then(function(token) { ... });
OR
exports.getAccessToken = function(res, cb) {
...
request(options, function(errror, response, body) {
var token = JSON.parse(body).access_token;
cb(token);
}
}
// Use it like
getAccessToken(res, function(token) { ... });

How do I send requests in a for loop synchronously in nodejs?

I'm trying to make facebook api requests in a for loop using request module in nodejs. But I need to make the loop and request calls synchronous. What am I doing wrong?
async function sendRequestAsync(sender, messageData) {
await request({
url: "https://graph.facebook.com/v2.6/me/messages",
qs: {access_token: PAGE_ACCESS_TOKEN},
method: "POST",
json: {
recipient: {id: sender},
message: messageData
}
});
}
function sendFoods (sender, results) {
results.forEach(async result => {
await request.sendRequestasync(sender, {text: result.cat});
await request.sendRequestasync(sender, result.data);
console.log(result);
});
}
In ES8 Async/Await the script waits for resolving a promise before it continues the execution.
async function test() {
for (let i = 0; i < 5; i++) {
let result = await req('http://google.com');
console.log(result.resp.statusCode, i);
};
};
function req(url) {
return new Promise(function(resolve, reject) {
request.get(url, function(err, resp, body) {
if (err) { reject(err); }
else { resolve({resp: resp, body: body}); }
})
})
};
Try my live example
Your sendRequestAsync function should just return the promise directly from the request call rather than awaiting it. Await is really just syntactic sugar for .then ().

Regressive call in promise

Is there any easy way to do recursive call using promise. Here is my sample.
function getData() {
var result=[];
var deferred = Q.defer();
(function fetchData(pageno){
var options = {
method : 'GET',
url : 'example.com/test',
qs:{
pageNo: pageno
}
}
request(options, function (error, response, body) {
if (error)throw new Error(error);
if (body.hasMorePage == true) { //checking is there next page
result.push(body)
fetchData(++body.pageno); // getting next page data
} else {
deferred.resolve(result); // promise resolve when there is no more page
}
});
})(0);
return deferred.promise;
}
getData().then(function(data){
console.log(data)
});
Let's consider API is giving more data in consecutive calls. in order to collect all the data, I need to use some parameter (EX:hasMorePage) from previous call response. I need to go regressive call only for obtaining this scenario, but I would like to know a better(Promise) way.
Most welcome.
async function request(options, callback) {
// simulate server response of example.com/test with 1 second delay
const totalNumberOfPages = 3;
const pageNo = options.qs.pageNo;
await new Promise(resolve => setTimeout(resolve, 1000));
const hasMorePages = pageNo < totalNumberOfPages;
const body = { hasMorePages };
callback(void 0, { body }, body);
}
function getPage(pageNo) {
const options = {
method: 'GET',
url: 'example.com/test',
qs: { pageNo }
};
return new Promise(resolve => request(options, (error, response, body) => {
console.log('response received', response);
if(error) {
throw new Error(error);
}
resolve(body);
}));
}
async function getData() {
const result = [];
for(let i = 1, hasMorePages = true; hasMorePages; i++) {
const body = await getPage(i);
result.push(body);
hasMorePages = body.hasMorePages;
}
return result;
}
getData().then(data => console.log('RESULT', data));

Q.all array of request promises, not sure how to get the results

Probably an obvious answer to this but I'm not sure what way to take.
request is a node module: https://github.com/request/request
I fill an array of getHistory requests (with different parameters). p = [p1,p2...].
this.app.all('/api/heatmap', function(req,res) {
// fill p here _.each(blabla, p.push(gethistory(someparams...)
var result = [];
function getHistory(params) {
var options = { ...};
var callback = function(error, response, body) {
if(error) { //wtv
} else {
// what to do with the body here ? return body ? result.push(body) ?
}
}
request(options, callback);
}
Q.all(p).then(function() {
});
}
So the problem here is that I when all of the request to be done , put everything in an array/object then send the whole thing to the client. How to have getHistory returning the fetched value (after the request is done ).
Hope it's clear.
The core problem here is that node.js-style callbacks and promises are not compatible. Promises emphasize on return values, node emphasizes on callbacks.
Therefore you need a sort of adapter that wraps node's callback convention properly, a process called Promisifcation. This can be done manually, but it's tedious at best and error-prone when you are not careful. Luckily, since node's conventions are well-established, it can be automated. Q has a few helpers for that, but Bluebird is quite a bit more convenient in this regard.
So the easy way to do it is to switch to Bluebird as the promise library and to use promisifyAll.
var Promise = require('bluebird');
var request = Promise.promisifyAll(require("request"));
this.app.all('/api/heatmap', function(req, res) {
var requests = blabla.map(function (item) {
return request.getAsync({ /* params */ });
});
Promise.all(requests).then(function (responses) {
res.send( JSON.stringify(responses) ); // whatever
}).catch(function (error) {
res.send( "An error ocurred: " + error ); // handle error
});
}
FWIW, here's another answer that shows how the same would look like when done properly with Q:
// promisified request
function requestAsync(options) {
var result = Q.defer();
request(options, function(error, response, body) {
if (error) {
result.reject(error);
} else {
result.resolve(body);
}
});
return result.promise;
}
// returns promises for heatmapVolumes
function getHistory(params) {
return requestAsync({
method: 'GET',
url: 'https://api.kaiko.com/v1/charts/' +
encodeURIComponent(params.exchange) + '/' +
encodeURIComponent(params.pair) +'/history',
qs: params.qs,
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
}).then(function (body) {
return heatmapVolume(body, params.exchange, params.pair);
}).catch(function (error) {
// log detailed error and send less revealing message downstream
console.error('error fetching trades', error);
throw new Error('Something went wrong while fetching trades');
});
}
// usage
this.app.all('/api/heatmap', function(req, res) {
getHistory({
exchange: "foo", pair: "bar", qs: "qux"
}).then(function (heatmap) {
res.send(200, heatmap);
}).catch(function (error) {
res.send(500, error);
});
});
Used Q.deferred and it worked as documented \o/
function getHistory(params) {
var deferred = Q.defer();
var options = {
method: 'GET',
url: 'https://api.kaiko.com/v1/charts/' + params.exchange + '/' + params.pair +'/history',
qs:qs,
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
}
var callback = function(error, response, body) {
if(error) {
console.log('error fetching trades', error);
res.send(500, 'Something went wrong while fetching trades');
} else {
var body = heatmapVolume(body, params.exchange, params.pair);
// console.log("result!", body.exchange, body.pair);
result.push(body);
// return body;
deferred.resolve();
}
}
request(options, callback);
return deferred.promise;
}

Resources