Node.js pass values from one api to another - node.js

I need to get the value of "data":3 from API1 and check in API2 if the field "data" has value greater than or equal to 3. I need to create a new API with API2 fields alone passing the filter criteria, please check the desired Json:
Json :
[
{
"fieldid": "0001",
"data": 3 , ---- API 1
"field7": "2018-12-06T11:49:52.389Z"
},
[
{
"field1": "E004",
"data": 3, --- api 2
"field7": "2018-12-06T11:49:52.389Z"
},
{
"field1": "E005",
"data": 2, ---- api 2
"field7": "2018-12-06T11:49:52.389Z"
}
],
]
Function :
n getlistofStaffs(req, callback) {
log.info(path.basename(module.filename), "List Staffs :: getlistofStaffs()");
var listofStaffsAPI = api url;
const requestOptions = {
url: listofStaffsAPI,
json: true
};
request(requestOptions, function (err, res, body) {
if (err) {
return callback(true, null);
} else if (res.statusCode == 200) {
var clearancesstaff=body[0].clearanceLevel;
var staffClearanceId = body[0].staffClearanceId;
return callback(null, {staffClearanceId:body[0].staffClearanceId,clearancesstaff:body[0].clearanceLevel});
}
});
}
Desired Output JSON :
[ {
"fieldid": "0001",
"data": 3 ,
"field7": "2018-12-06T11:49:52.389Z"
}
]
Thanks

Since you're using the async library, you'll want to make use of the .waterfall() method, which passes the callback data from one callback to the input of the next function. Since I'm not entirely sure what your existing functions do, I'll demonstrate the signature I think is necessary to what you're trying to do, but leave the details up to you.
function getListofStaffs(req, callback) {}
function getListofEvents(req, fieldname, callback) {}
// later
module.exports = (req, res, next) => {
async.waterfall([
getListofStaffs.bind(null, req),
getListofEvents.bind(null, req)
], (err, results) => {
if (err) return next(err);
return res.send(results);
});
}
If you're able to do it, it may be slightly more easy to follow your code if you're able to use the async/await features available in the last few versions of node. If you can, then you'll just make sure your API calls return Promises, and then you can do this:
async function getListofStaffs(req) {}
async function getListofEvents(req, fieldname) {}
module.exports = async (req, res, next) => {
try {
const fieldname = await getListofStaffs(req);
const events = await getListofEvents(req, fieldname);
res.send({ fieldname, events });
} catch (err) {
return next(err);
}
}
There's also the asynchandler module you can use if you don't want try..catch blocks in your routes.
EDIT
As mentioned in my comment, you need to update your getListofEvents function to expect three parameters, based on your current design:
function getlistofEvents(req, clearanceData, callback) {
var dt = dateTime.create();
var formatted = dt.format('Y-m-d');
console.log(formatted);
console.log(clearanceData);
log.info(path.basename(module.filename), "List Events :: getlistofEvents()");
var listofEventsAPI = www.gmail.com;
const requestOptions = {
url: listofEventsAPI,
json: true
};
request(requestOptions, function (err, res, result) {
if (err) {
return callback(true, null);
} else if (res.statusCode == 200) {
return callback(null, result);
}
});
}
Of course, your example code doesn't actually use that data, so I added a console.log to show it's there.

Related

weather app: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I am trying to build a weather app using node that takes
{
"cities": [
"toronto",
"mumbai",
"london"
]
}
as input and returns
{
"weather": {
"toronto": "24C",
"mumbai": "34C",
"london": "14C"
}
}
this as output
app.post('/getWeather',(req,res)=>{
const city = req.body.city;
city.map(city=>{
const url=`http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}`;
request(url, function(err, response, body) {
// On return, check the json data fetched
if (err) {
res.render('index', { weather: null, error: 'Error, please try again' });
} else {
let weather = JSON.parse(body);
console.log(weather);
Since the question does not have all of the code, I cannot give a definite answer, but I assume that the code either tries to sent response for the each city separately and/or does not wait for all the API calls to finish.
To fix the issue, async/await needs to be used (since the response depends on several API calls), and response must be sent after its completely assembled.
An example based on the given code:
app.post("/getWeather", async (req, res) => {
const cities = req.body.cities;
const reqs = cities.map((city) => {
const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}`;
return new Promise((resolve, reject) => {
request(url, function (err, response, body) {
if (err) {
reject(err);
} else {
let weather = JSON.parse(body);
resolve(weather);
}
});
});
});
const responses = await Promise.all(reqs);
const result = {};
for (const response of responses) {
if (response.ok) {
result[response.city] = response.temp;
}
}
res.json(result);
});

node.js module.exports returns undefined

I'm new to node.js, and I'm trying to return a value from a function, but for some reason it's not working as planned.
In the code below, I want to return AuthToken from within the Try statement, but instead, it returns the values from outside the Try statement. If I delete that return line, then it just returns undefined. If I add return AuthToken instead then it also returns undefined - obviously because it hasn't completed the Try statement...
I've checked out a bunch of similar problems, but they haven't answered my problem.
Any suggestions?
"use strict";
const request = require('request'); // node package to create api request
var AuthToken;
/*
some stuff
*/
module.exports = {
FUNC1: (param1) => {
/*DO STUFF */
},
FUNC2: (param2) => {
/*DO STUFF*/
},
GetAuthToken: () => {
var options = {
/*OPTIONS*/
};
try {
request(options, (err, resp, body) => {
if (!err) {
let data = JSON.parse(body);
AuthToken = data["accessToken"];
return AuthToken; // <= I expect the AuthToken to be returned here.
} else {
console.log(err)
}
})
} catch (err) {
console.log(err)
}
return "Here instead"; //<= But the function is returning here instead before it's performed the request...
},
}
I eventually figured out that the request function is an asynchronous and so needs to be called with an async function.
I took the example code from here and modified it for my purposes.

How to Ensure Data is Returned Before Variable Assignment (Node.js)

I am trying to retrieve data at multiple API endpoints simultaneously and aggregate the result to be sent back to the client as one response.
However, when trying to return data from async.parallel, I get an undefined result. I think this is because the result code is being executed before it is returned, but I am not sure.
I would like to pass an array of ids to the server, get their metadata, combine their metadata into one object, and send a single object back to the client.
function doSomething() {
for(let i=0; i<req.map.length; i++) {
stack[i] = (callback) => {
let data = subroute(req, res, req.map[i])
callback(null, data)
}
}
async.parallel(stack, (err, result) => {
if(err) {
// Handle error
} else {
console.log(result) // Logs undefined
res.json([result]) // Would like to send this result back to the client
}
})
}
function subroute(req, res, num) {
request({
url: 'https://example.com/api/endpoint/' + num
},
(error, response, body) => {
if(error) {
res.json({ "error": error })
} else {
let i = {
name: body.name,
age: body.age,
}
return i
}
})
}
How can I accumulate the results of many API endpoint responses on the server and send the back as one response to the client?
Change
let data = subroute(req, res, req.map[i])
callback(null, data)
to
subroute(req, res, req.map[i], callback)
Subsequently, change subroute to receive the callback and return the return
function subroute(req, res, num, cb) {
request({
url: 'https://example.com/api/endpoint/' + num
},
(error, response, body) => {
if(error) {
res.json({ "error": error })
cb(<whatever error you would want to pass>);
} else {
let i = {
name: body.name,
age: body.age,
}
cb(null, i);
}
})
}
By doing let data = subroute(req, res, req.map[i]) you are assigning the result of subroute call to data. Notice subroute does not have a return statement in the function body so data will always be undefined.

res is not defined in Node.js (Mongoose)

How can I put res in a normal function i.e not an exported one which is not part of routes?
function createNewStudent(v,callBackOne){
if (callBackOne) {
studentInfo.callBackOneStudent = callBackOne;
}
// common filter json
var filterjson = common.defaultFilterJson();
filterjson['active'] = true;
filterjson['email'] = v.email;
// student initialization
var student = new Student(v);
async.waterfall([
function (done) {
student.save(function (err) {
if (!err) {
studentInfo.callBackOneStudent();
Employee.update({_id: student.created_by},{"$push": { "students": student._id } }).exec(function (err, employee) { });
done();
}
});
}
}
});
},
function (done) {
var url = config.mailer.studentActivateUrl + student._id;
---error is here-----
res.render('modules/users/server/templates/student-confirmation-email', {
name: student.first_name + ' ' + student.last_name,
appName: 'GAIPP',
url: url
}, function (err, emailHTML) {
done(err, emailHTML, student);
});
}
});
My error is 'res' is not defined. Can anyone please help me to solve this error?
The only way that you can put res in a function is if you somehow supply it to that function at runtime. Remember that res is meaningful only in request handling. Outside of the request handler your function couldn't even know which request to respond to because there might be several requests served at the same time.
If you want to have a function that has access to res then you have those options:
Use a nested function in your request handler, e.g.
app.get('/foo', function (req, res) {
function x() {
// you can use res here
}
x();
});
Add res as an argument:
function x(res) {
// you can use res here
}
app.get('/foo', function (req, res) {
x(res);
});
Another option would be to add a callback to your function that would be passed by the handler:
function x(args, cb) {
// you cannot use res here
// but you can call the callback:
cb(null, 'something');
}
app.get('/foo', function (req, res) {
x(function (err, data) {
if (err) {
// handle error
}
// use res here with data supplied by x()
res(data);
});
});
Instead of using callback your x() function could also return a promise.

How to add field to mongoose query result?

exports.getCityCascade = function (req, res) {
var result = {};
Province.find().exec(function (err, provinces) {
result.provinces = provinces;
var provinceCount = 0;
async.whilst(
function () {
return provinceCount < provinces.length
}
, function (callback) {
City.find({province: provinces[provinceCount].id}).exec(function (err, cities) {
if (err) {
callback(err);
} else {
result.provinces[provinceCount].cities =cities;
}
provinceCount++;
callback(null , result);
});
}, function (err, result) {
if (err) return res.jsonp({message: err.message});
return res.jsonp({
status: '200',
results: result});
}
)
})
}
When I add the cities field to provinces, It seems doesn't work. the response body doesn't contain the filed cities. How to fix it? Any advice would be very helpful.
The problem is just a conflict between variable names: you declared a var result outside Province.find(), but the async.whilst() also uses result as the second argument of its callback function. Just rename one of them and it should work.

Resources