Nodejs Q promise catch never called with passport js - javascript

I'm using the passport library for node to assist me in user signup. I'm also using the 'Q' promise library to avoid the pyramid of doom as I go through several asynchronous steps.
Everything works fine, until I throw an error from one of the promised steps. I would have assumed execution would drop into the .fail function, where I could handle the error and return out of passport with a failed signup. But for a reason that I don't understand, the .fail function never gets called. Instead, I just get a stackdump in my browser window and in my console.
The controlling code is here:
q.fcall(checkEmailIsFree({'email':email, 'username':username, 'password':password}))
.then(checkUsernameIsFree)
.then(registerUser)
.then(function (user) {
if (user) {
logDebug('REGISTERED: ' + email);
return done(null, user);
}
else {
logDebug('Could not register');
return done(null, false);
}
})
.fail(function (err) {
logError('I never get here');
return done(null, false);
})
.done();
And here's how I'm throwing, from within checkEmailIsFree
var error = new Error('Bad times. Email is in use: ' + email);
throw error;
Is there some overall express / node code somewhere that is set to fast dump out an exception somehow? Why isn't my catch being called? What am I missing?

I think done(onFulfilled, onRejected, onProgress) can help in this case. You can try:
q.fcall(checkEmailIsFree({'email':email, 'username':username, 'password':password}))
.then(checkUsernameIsFree)
.then(registerUser)
.then(function (user) {
if (user) {
logDebug('REGISTERED: ' + email);
return done(null, user);
}
else {
logDebug('Could not register');
return done(null, false);
}
})
.done(undefined, function (err) {
logError('Error!'); // used in case of reject
return done(null, false);
});

Related

Why isn't try catch blocks catching exceptions

So I have this piece of code that works fine, but if there is an error with the data type the try catch blocks are not working. It appears I am going to have to check all data types before using them to ensure my server doesn't crash.
For instance in the following code, If tokens for some reason wasn't an array, when the error get's thrown, my try catch isn't catching the error. Instead it is crashing the server.
router.patch("/updateDeviceToken", checkIfAuthenticated, (req, res) => {
try {
console.log("In updating contacts");
console.log("body", req.body);
User.findById(req.authId, (error, user) => {
try {
if (error) {
console.log(error);
console.log("user found");
return res.status(404).json(error);
}
if (!user) return res.status(401).json("User not found");
if (
req.body.android &&
!user.tokens.android.includes(req.body.android)
) {
user.tokens.android.push(req.body.android);
user
.save()
.then((user) => {
console.log("token updated");
return res.json("Token updated");
})
.catch((error) => res.status(404).json(error));
} else if (req.body.iOS && !user.tokens.iOS.includes(req.body.iOS)) {
user.tokens.iOS.push(req.body.iOS);
user
.save()
.then((user) => {
console.log("token updated");
return res.json("Token updated");
})
.catch((error) => res.status(404).json(error));
} else {
console.log("token received but not updated");
return res.json("Token received but not updated");
}
} catch (e) {
console.log(e);
return res.status(404).json("There was an error");
}
});
} catch (e) {
console.log(e);
}
});
try catch doesnt work well with then
Can you change code to use promises with await / async ?
You can use try catch with it
I struggled with that as it is easily overlooked in the documentation but For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the next() function, where Express will catch and process them. For example:
app.get('/', function (req, res, next) {
fs.readFile('/file-does-not-exist', function (err, data) {
if (err) {
next(err) // Pass errors to Express.
} else {
res.send(data)
}
})
})
You can also write your custom error handler, long read but it will save you a lot of time.

done() vs return done()

I was reading the docs for passport and I noticed that with serialize() and deserialize() done() is called with out being returned.
However when setting up a new strategy using passport.use() in the callback function return done() is used.
Is this something that needs to be understood or just copied from the docs?
http://www.passportjs.org/docs/
From the docs:
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
return done() will cause the function to stop executing immediately. This means that any other lines of code after that line inside the function will be ignored and not evaluated.
done() not preceded by return, however, will not cause the function to stop executing. This means that any other lines of code after that line inside the function will be evaluated.
If you take a look at this passport.use() example (from the Passport docs), you'll see there is reachable code after the first three return done() statements, and you would want the function to exit immediately as soon as done() is called the first time to make sure none of the following instructions are evaluated:
passport.use(new BasicStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.validPassword(password)) { return done(null, false); }
// The following line is the success case. We do not want to execute it
// if there was an error, a falsy user or a user without a valid
// password. If we removed the return keywords from the previous lines
// of code, the success case would be triggered every time this
// function was called
return done(null, user);
});
}
));
Here I've added two executable snippets to illustrate the difference between done() and `return done(). The snippets are otherwise identical.
done() without return:
const done = console.log
const assessThreatLevel = threatLevel => {
if (threatLevel === 'all good') done('relax :)')
done('launch the missiles!')
}
assessThreatLevel('all good')
`return done():
const done = console.log
const assessThreatLevel = threatLevel => {
if (threatLevel === 'all good') return done('relax :)')
done('launch the missiles!')
}
assessThreatLevel('all good')
As an aside, I have taken to using return done() in most situations for consistency. As far as I'm aware, there's no drawback to using it. It can help you avoid bugs, and the return statement serves as a guarantee and a good visual reminder that the function will exit immediately after that statement is evaluated.

Why can I get a Bluebird catch in the middle of chain stop the rest of the chain execution

I am building this promise chain. The goal is to have the first action check for uniqueness on a field in the DB, and then if unique, save the object. But if the object is not unique, it should not save, and should return an error response.
function(request, reply) {
var payload = request.payload;
checkThatEmailDoesNotExist().then(saveUser)
function checkThatEmailDoesNotExist() {
return User.where({email: payload.email}).countAsync()
.then(function(count) {
if (count > 0) {
throw Boom.badRequest('The email provided for this user already exists')
}
return null;
})
.catch(function(err) { // ~This catch should stop the promise chain~
reply(err);
})
}
function saveUser() {
// ~But instead it is continuing on to this step~
return User.massAssign(request.payload).saveAsync()
.spread(function(user, numAffected) {
return reply(user);
})
.catch(function(err) {
server.log(['error', 'api', 'auth'], err);
throw Boom.badRequest('Object could not be saved to database');
});
}
}
If an error is thrown in the checkThatEmailDoesNotExist() it's catch() should return the error, and stop processing the rest of the original promise chain.
Instead of acting that way, the catch() fires, and then continues to move on to the saveUser() function.
You are mixing promises and callbacks which is a horrible anti-pattern. The caller will simply use
the returned promise, there is no need to manually wire things back to callbacks.
function save(request) {
var payload = request.payload;
return User.where({email: payload.email}).countAsync()
.then(function(count) {
if (count > 0) {
throw Boom.badRequest('The email provided for this user already exists')
}
return User.massAssign(request.payload).saveAsync()
})
.get(0)
/* equivalent to
.spread(function(user, numAffected) {
return user;
}) */
.catch(Promise.OperationalError, function(err) {
server.log(['error', 'api', 'auth'], err);
throw Boom.badRequest('Object could not be saved to database');
});
}
Usage:
save(request).then(function(user) {
response.render(...)
}).catch(function(e) {
response.error(...)
})
If you wanted to expose a callback api, the sane way to do that is to bolt on a nodeify at the end of an existing promise api and call it a day:
function save(request, callback) {
var payload = request.payload;
return User.where({email: payload.email}).countAsync()
.then(function(count) {
if (count > 0) {
throw Boom.badRequest('The email provided for this user already exists')
}
return User.massAssign(request.payload).saveAsync()
})
.get(0)
/* equivalent to
.spread(function(user, numAffected) {
return user;
}) */
.catch(Promise.OperationalError, function(err) {
server.log(['error', 'api', 'auth'], err);
throw Boom.badRequest('Object could not be saved to database');
})
.nodeify(callback);
}
save(request, function(err, user) {
if (err) return response.error(...);
response.render(...);
});

How to use Promise in Sequelize Js to return a Entity

var user = db.User.find({ where: { username: username }}).then(function(user) {
console.log("Authenticate"+user.authenticate(password));
if (!user) {
return null;
} else if (!user.authenticate(password)) {
return null;
} else {
return user;
}
}).catch(function(err){
return err;
});
I am Using Sequelize JS with Node JS.
I want the object of the user that matches the where clause.
but when I do return from then function . but it goes into infinite loop.
I am new to Node Js and I don't know how to use Promise in Node Js.
Please help mee
The return value from db.User.find() is a promise. It will never be a user, so your first line is incorrect.
What you'll need to do is call the next function in your processing chain from within the promise then callback. This is the standard practice in Node.
If you return something from a then promise callback it's assumed to be another promise, which allows you to chain multiple promises in a row (example). That's not what you're looking for.
Your example would be better as something like:
function authentication(err, user){
// Do something
}
db.User.find({ where: { username: username }}).then(function(user) {
console.log("Authenticate"+user.authenticate(password));
if (!user) {
authentication(null, null);
} else if (!user.authenticate(password)) {
authentication(null, null);
} else {
authentication(null, user);
}
}).catch(function(err){
authentication(null, user);
});
Note the use of a callback to signify the result of your authentication test. Note also err as the first parameter to the callback, which is standard Node convention.
Try to use try and catch block
Here is an example:
authentication: async (req,res) => {
try {
let user = await User.findOne({
where: {username: req.body.username}
});
user = user.toJSON();
console.log(user);
if (!user) {
console.log('Not a user');
}
}
catch (e) {
console.log(e)
}
}

Chaining promises with then and catch

I'm using the bluebird Promise library. I'd like to chain promises and catch specific promises errors. Here's what I'm doing :
getSession(sessionId)
.catch(function (err) {
next(new Error('session not found'));
})
.then(function (session) {
return getUser(session.user_id);
})
.catch(function (err) {
next(new Error('user not found'));
})
.then(function (user) {
req.user = user;
next();
});
But if an error is thrown by getSession, the two catch are called, as well as the second then. I'd like to stop the error propagation at the first catch, so that the second catch is only called when getUser throws, and the second then when getUser succeeds. What do?
The promise that is returned by the .catch method will still be resolved with the result of the callback, it doesn't just stop the propagation of the chain. You will either need to branch the chain:
var session = getSession(sessionId);
session.catch(function (err) { next(new Error('session not found')); });
var user = session.get("user_id").then(getUser);
user.catch(function (err) { next(new Error('user not found')); })
user.then(function (user) {
req.user = user;
next();
});
or use the second callback to then:
getSession(sessionId).then(function(session) {
getUser(session.user_id).then(function (user) {
req.user = user;
next();
}, function (err) {
next(new Error('user not found'));
});
}, function (err) {
next(new Error('session not found'));
});
Alternatively, the better way would to just propagate the errors through the chain, and call next only in the very end:
getSession(sessionId).catch(function (err) {
throw new Error('session not found'));
}).then(function(session) {
return getUser(session.user_id).catch(function (err) {
throw new Error('user not found'));
})
}).then(function (user) {
req.user = user;
return null;
}).then(next, next);
Since you're using bluebird for promises, you actually don't need a catch statement after every function. You can chain all your thens together, and then close the whole thing off with a single catch. Something like this:
getSession(sessionId)
.then(function (session) {
return getUser(session.user_id);
})
.then(function (user) {
req.user = user;
next();
})
.catch(function(error){
/* potentially some code for generating an error specific message here */
next(error);
});
Assuming the error messages tell you what the error is, it's still possible to send an error specific message like 'session not found' or 'user not found', but you'll just have to look into the error message to see what it gives you.
Note: I'm sure you probably have a reason for calling next regardless if there's an error or not, but it might be useful to throw in a console.error(error) in the case that you get an error. Alternatively, you could use some other error handling function, whether it's a console.error, or res.send(404), or something of the like.
I am using it like that:
getSession(x)
.then(function (a) {
...
})
.then(function (b) {
if(err){
throw next(new Error('err msg'))
}
...
})
.then(function (c) {
...
})
.catch(next);

Categories

Resources