Waiting for multiple async calls using async.each - javascript

I need to wait for few async calls to complete before resuming execution. I tried the following code using async.
asana.getUsers(null, function(error, resp){
async.each(resp.data, function(user, cb) {
console.log("Get info for user : ", user.id);
asana.getUser(user.id, null, function(error, userResp){
console.log("user response: ", userResp.data.id);
userEmailList.push({
id : userResp.data.id,
name: userResp.data.name,
email : userResp.data.email
});
cb(null);
});
//cb(null); Should the call be here??
}, function(err){
console.log("getUsers is done now");
});
});
The log that i get is:
Get info for user : xxxxxxxxxxxx
Get info for user : yyyyyyyyyyyy
Get info for user : zzzzzzzzzzzz
Get info for user : aaaaaaaaaaaa
user response: yyyyyyyyyyyy
/Code/javaScript/NodeWorkspace/asana-api/mail.js:23
console.log("user response: ", userResp.data.id);
^
TypeError: Cannot read property 'data' of null
at /Code/javaScript/NodeWorkspace/asana-api/mail.js:23:43
at Request._callback (/Code/javaScript/NodeWorkspace/asana-api/lib/asana.js:77:13)
at Request.self.callback (/Code/javaScript/NodeWorkspace/asana-api/node_modules/request/main.js:119:22)
at Request. (/Code/javaScript/NodeWorkspace/asana-api/node_modules/request/main.js:525:16)
at Request.EventEmitter.emit (events.js:95:17)
at IncomingMessage. (/Code/javaScript/NodeWorkspace/asana-api/node_modules/request/main.js:484:14)
at IncomingMessage.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:883:14
at process._tickCallback (node.js:415:13)
I understand the first logs, but why is the console.log("user response: ", userResp.data.id); line getting called with userResp as null.
I hope its not some silly mistake. Thanks in advance.
P.S: Basically i need to get Asana users and then get info of each user and store in a var userEmailList.

The issue was that userEmailList was undefined.

Related

cant set headers after they are set

Im trying to get the idsFromMongo I saved in my neo4j database and search for those ids in the mongodb to return the objects I want. It works 1 time but then my server crashes and it returns the error Can't set headers after they are sent.
This is my code:.
routes.get('/advertisements/recommended/:brand', function(req, res) {
res.contentType('application/json');
var brandFromUrl = req.params.brand;
var advertisementIds = [];
Advertisement.find({'car.brand': brandFromUrl})
.then(function (ads) {
// res.status(200).json(ads);
ads.forEach(function (record) {
console.log('ids: ' + record._id)
session
.run("MERGE(a:Advertisement {idFromMongo: {idParam}, brand: {brandParam}}) WITH a MATCH(b: Advertisement {brand: {brandParam}}) MERGE(a)-[:SHARED_BRAND]->(b)", {idParam: record._id.toString(), brandParam: brandFromUrl})
.then(function(result) {
session
.run("MATCH (n:Advertisement{brand: {brandParam}}) RETURN (n)", {brandParam: brandFromUrl})
.then(function(result) {
result.records.forEach(function(record){
advertisementIds.push(record._fields[0].properties.idFromMongo);
});
Advertisement.find({
'_id': { $in: advertisementIds}
}, function(err, docs){
res.status(200).json(docs);
})
})
})
});
})
.catch((error) => {
res.status(400).json(error);
});
});
This is my error:
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:494:11)
at ServerResponse.setHeader (_http_outgoing.js:501:3)
at ServerResponse.header (c:\dev\individueel-project\individueel-database\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (c:\dev\individueel-project\individueel-database\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (c:\dev\individueel-project\individueel-database\node_modules\express\lib\response.js:267:15)
at c:\dev\individueel-project\individueel-database\api\advertisement.routes.v1.js:70:35
at model.Query.<anonymous> (c:\dev\individueel-project\individueel-database\node_modules\mongoose\lib\model.js:4046:16)
at c:\dev\individueel-project\individueel-database\node_modules\kareem\index.js:273:21
at c:\dev\individueel-project\individueel-database\node_modules\kareem\index.js:131:16
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
The problem here is you are executing an array and into the array you are sending the response. So, eventually it will send the responde several times, but only first time will work, after that it will raise an error.
To solve it, you should answer the request after the all promises into array has finished (Promise.all) or if you don't need to wait until the whole array has finished, check if you have already responded and don't do it again.

Can't find data from database after set it?

I have a piece of code which adds data to the database, then a function which gets the added data ID from the database. Problem is that, I get an error it couldn't be found, but it is in the database. How could I solve the problem?
[2017-06-03 18:01:25.855] [DEBUG] [default] - TypeError: Cannot read
property 'id' of undefined
Here is how the function looks like
function getLastUser(hash, socket, user){
query('SELECT * FROM users WHERE hash='+pool.escape(hash)+'', function(err, row){
if(err){
logger.error('Failed getting user hash: ' + user.name);
logger.debug(err);
socket.emit('message', {
type: 'error',
error: "Failed getting user hash"
});
return;
}
return row[0].id;
});
}
Here the calling
getLastUser(hash, user, socket);

Node/Express route not waiting for Redis server callback

What specific changes need to be made to the code below so that the res.json(...) command is NOT sent until any open calls to the Redis client.somecommand(..) have returned?
The code below is throwing an error related to the client.hmset(uname, { ... } trying to set a response header after res.json(...) was called. When I move the return res.json() commands to right after the end of the client.exists(uname, function(err, reply) { ... } conditional block, instead of their current locations inside the block, the anonymous token value is sent to the client app instead of the generated token value. This indicates that the callbacks to the Redis server have not returned.
How do I change the code below so that the res.json( ... ) commands cannot run until the Redis server callback has been returned? Ideally, there would be some conditional to wait a certain period before sending an error message if the Redis server callback takes too long.
Redis is added to the routes.js file containing all the code below, by adding the following two lines to the top of the file:
var redis = require('redis');
var client = redis.createClient();
Here are the various calls to the Redis server in the code below:
client.exists(uname, function(err, reply) { ... }
client.hgetall(uname, function(err, object) { ... }
client.hmset(uname, { ... }
client.expire(uname, 10);
The complete code for the Node.js/Express.js API route is:
app.get('/user**', function(req, res) {
console.log("You Hit The User Route TOP");
request({
method: 'GET',
url: authServer + '/uaa/user',
json: true,
auth: {
user: null,
password: null,
sendImmediately: true,
bearer: bearerToken
}
}, function (error, response, body) {
if(error){
console.log('ERROR with user request.');
return res.sendStatus(500);
}
else {
var uname = '';var jwtUser = 'empty';var jwtJSON = { "token" : "anonymous" }
console.log(response.statusCode);
if(body['name']){
uname = body['name'];console.log('uname is: ');console.log(uname);
if(uname.length > 0) {
scopesLocal = body['oauth2Request'].scope.toString();
client.exists(uname, function(err, reply) {//Check to see if a Redis key for the user already exists
if (reply === 1) {//a redis key DOES exist
console.log('\"'+uname+'\" exists');
client.hgetall(uname, function(err, object) {//retrieve all the values in the hash/object that we just set
if(object) {
if(object["jwt"]) {
console.log('object[\"jwt\"] is: ');console.log(object["jwt"]);
jwtJSON = { "token" : object["jwt"] };
console.log('jwtJSON is: ');console.log(jwtJSON);
return res.json(jwtJSON);
}
}
});
} else {//a redis key DOES NOT exist
console.log('\"'+uname+'\" doesn\'t exist');
jwtUser = generateJwt(uname, authoritiesLocal);
client.hmset(uname, {//store a hash/object
'AccessToken': body['details'].tokenValue,
'TokenType': body['details'].tokenType,
'Authenticated': body['authenticated'],
'Principal': body['principal'],
'Scopes': scopesLocal.toString(),
'Authorities' : authoritiesLocal,
'jwt' : jwtUser
});
jwtJSON = { "token" : jwtUser };console.log('jwtJSON is: ');console.log(jwtJSON);
return res.json(jwtJSON);
}
client.expire(uname, 10);//set the key to expire in 10 seconds. use this to manage session length
});//end of Redis conditional block
console.log('jwtJSON is: ');console.log(jwtJSON);
} else { console.log('uname is empty!'); }
return res.json(jwtJSON);
}
};
});
console.log("You Hit The User Route BOTTOM");
});
The error message in the nodemon terminal is:
_http_outgoing.js:346
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
at ServerResponse.header (/home/user/nodejs_apps/oauth_seed_app/node_modules/express/lib/response.js:719:10)
at ServerResponse.json (/home/user/nodejs_apps/oauth_seed_app/node_modules/express/lib/response.js:247:10)
at Command.callback (/home/user/nodejs_apps/oauth_seed_app/app/routes.js:112:44)
at normal_reply (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis/index.js:714:21)
at RedisClient.return_reply (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis/index.js:816:9)
at JavascriptRedisParser.Parser.returnReply (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis/index.js:188:18)
at JavascriptRedisParser.execute (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis-parser/lib/parser.js:413:12)
at Socket.<anonymous> (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis/index.js:267:27)
at emitOne (events.js:90:13)
at Socket.emit (events.js:182:7)
at readableAddChunk (_stream_readable.js:153:18)
at Socket.Readable.push (_stream_readable.js:111:10)
at TCP.onread (net.js:534:20)
I read this posting about the specific error message. And I read this other posting about how to wait for a callback. I also read this posting about Redis callbacks to Node. But I do not see how to apply the answers to either of those other postings to the Redis callback problem in the code above.
The problem was that the return res.json(jwtJSON); commands in the OP were NOT segregated into discrete if...else blocks.
The solution is:
if(something) {
//populate jwtJSON with a real JWT
return res.json(jwtJSON);
} else {
return res.json(jwtJSON);//this leaves the anonymous value
}
Doing this segregation for every nested condition in the above code got rid of the problem.

Dynamo DB getItem with node js throwing error

I am new to Javascript and DynamoDB. I am trying to perform getitem using aws-sdk for javascript in nodejs. primary index of Dynamo table Cars is "name" a string.
var AWS = require('aws-sdk');
AWS.config.region='eu-west-1';
var db = new AWS.DynamoDB();
var params = {
TableName : 'Cars',
Key : {
"name" : {
"S" : "Volkswagen Dasher"
},
}
}
db.getItem(params, function(err, data) {
if (err) {
console.log(err); // an error occurred
}
else {
console.log(data); // successful response
}
return next();
});
On running the above .js file I am getting the following error.
ubuntu#ubuntu:~/node$ node getItem.js
{}
/home/ubuntu/node_modules/aws-sdk/lib/request.js:30
throw err;
^ ReferenceError: next is not defined
at Response.<anonymous> (/home/ubuntu/node/getItem.js:21:10)
at Request.<anonymous> (/home/ubuntu/node_modules/aws-sdk/lib/request.js:353:18)
at Request.callListeners (/home/ubuntu/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
at Request.emit (/home/ubuntu/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
at Request.emit (/home/ubuntu/node_modules/aws-sdk/lib/request.js:595:14)
at Request.transition (/home/ubuntu/node_modules/aws-sdk/lib/request.js:21:10)
at AcceptorStateMachine.runTo (/home/ubuntu/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /home/ubuntu/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/home/ubuntu/node_modules/aws-sdk/lib/request.js:37:9)
at Request.<anonymous> (/home/ubuntu/node_modules/aws-sdk/lib/request.js:597:12)
Plz help me out. Cheers!
Glad to see you're giving DynamoDB a try! I'm not really sure I understand the context of your code, but if your goal is to make a simple GetItem call, you don't need the 'return next()' statement. Given javascript's event driven nature, these callbacks are asynchronous and don't really "return" anything. Instead, you should inspect the response (data) and perform an action accordingly.
I.E.
dynamoDB.getItem(params, function(err, data) {
if (data) {
doSomethingWithItem(data.Item);
}
});
Also, if you're just starting out I would recommend taking a look at the document-js-sdk which a wrapper on top of the original SDK to allow you to use literals such as "string" instead of {S: "string"}.

How do I pass error messages from meteor server to client

I am using a meteor method to retrieve values from a client side function. I am using stripe api, it is working fine
However when there is a error in the stripe.charges.create function the error is not passed back to the client, which results in the stripeCheckout method sending the user to the complete template. I assume there is a way to take the errors in the Stripe.charges.create err.type response from stripes servers or the Stripe.customers.create function on the server side pass them to the client and let the user know the specific error as well as not sending them to the complete template using a if statement based on errors or Status of success from the stripe server which is passed to the meteor.
It's that connection from the error response from stripes 'Stripe.charges.createfunction to the meteor server and then passing it back to the client through thestripeCheckout` method.
Ok Hope I can get this solved. And any tips to approach this token creation, customer creation and charge in better practice, I am open to any suggestions.
Thanks!
Client JS
Stripe.card.createToken({
number: $('.card-number').val(),
cvc: $('.card-cvc').val(),
exp_month: $('.card-expiry-month').val(),
exp_year: $('.card-expiry-year').val(),
address_line1: addressValue1,
address_line2 : addressValue2,
address_city: cityValue,
address_state: provinceState,
address_country: country,
address_zip: zip,
name: firstName + lastName
}, stripeResponseHandler);
function stripeResponseHandler(status, response) {
if (response.error) {
alert(response.error.message);
}else{
// response contains id and card, which contains additional card details
var token = response.id;
Meteor.call('stripeCheckout',token, function (error, result) {
Router.go("/complete");
});
}
}
Server JS
Meteor.methods({
stripeCheckout: function (token) {
Stripe.customers.create({
source: token
}, function(err, customer) {
id = customer.id;
if(err){
throw new Meteor.Error("create-failed", err.message);
}else{
throw new Meteor.Error("create-failed", err.message);
}
Stripe.charges.create({
amount: 1000,
currency: 'usd',
customer: id
}, function (err, res) {
if(err){
throw new Meteor.Error("create-failed", err.message);
}else{
throw new Meteor.Error("create-failed", err.message);
}
});
});
}
});
UPDATE:
I added my current error detecting, I throw a error in all instances and I get this response in my console.
Exception in delivering result of invoking 'stripeCheckout': TypeError: Cannot read property 'error' of undefined
at http://localhost:3000/client/stripeClient.js?0eb126fd5e018d3cac3f8ec1505f32b7fdc97604:197:22
at Meteor.bindEnvironment [as _callback] (http://localhost:3000/packages/meteor.js?81e2f06cff198adaa81b3bc09fc4f3728b7370ec:977:22)
at _.extend._maybeInvokeCallback (http://localhost:3000/packages/ddp.js?41b62dcceb3ce0de6ca79c6aed088cccde6a44d8:3858:12)
at _.extend.receiveResult (http://localhost:3000/packages/ddp.js?41b62dcceb3ce0de6ca79c6aed088cccde6a44d8:3878:10)
at _.extend._livedata_result (http://localhost:3000/packages/ddp.js?41b62dcceb3ce0de6ca79c6aed088cccde6a44d8:4931:9)
at onMessage (http://localhost:3000/packages/ddp.js?41b62dcceb3ce0de6ca79c6aed088cccde6a44d8:3723:12)
at http://localhost:3000/packages/ddp.js?41b62dcceb3ce0de6ca79c6aed088cccde6a44d8:2717:11
at Array.forEach (native)
at Function._.each._.forEach (http://localhost:3000/packages/underscore.js?0a80a8623e1b40b5df5a05582f288ddd586eaa18:156:11)
at _.extend._launchConnection.self.socket.onmessage (http://localhost:3000/packages/ddp.js?41b62dcceb3ce0de6ca79c6aed088cccde6a44d8:2716:11)
This is the Stripe POST /v1/customers response
{
error:{
message: "Your card was declined."
type: "card_error"
code: "card_declined"
}
}
Simply throw a Meteor.Error like this:
Meteor.methods({
stripeCheckout: function (token) {
Stripe.customers.create({
source: token
}, function(err, customer) {
id = customer.id;
Stripe.charges.create({
amount: 1000,
currency: 'usd',
customer: id
}, function (err, res) {
// first argument is error code, second is error details
throw new Meteor.Error("create-failed", err.message);
});
});
}
});
You will get the error you threw in the error argument of the method callback.
See the docs here: http://docs.meteor.com/#/full/meteor_error

Categories

Resources