how to authenticate valid user in nodejs and mongo DB - node.js

I have a problem in validating user name and password in nodejs and mongodb . Below is the code what i tried. Password validation not working. what i am doing wrong here...
server.get('/login', function(req, res)
{
var status=""
user.findOne({name: req.query.username}, function(err, users)
{
if( err || !users)
{
console.log("No users found");
status="failed"
}
else
{
if(password==req.query.password)
{
status="success"
}
else
{
status="failed"
}
}
});
res.send(status);
});

Node.js runs on an asynchronous event loop, which means that your code won't necessary run the way you may always think it will (synchronously). To overcome this issue, there are a couple options: callbacks, or promises. Promises are generally the preferred route, and there are a couple libraries which I suggest: bluebird (is awesome) or async (which I haven't used a lot, but many prefer it).
If you'd like to work without promises for right now, you could fix your issue this way:
user.findOne({name: req.query.username}, function(err, users) {
if( !err && users && password === req.query.password ) {
res.send({ status: 'success' });
}
else { res.send({ status: 'failed' }); }
});
Again, the reason your code is not working is because the event loop reaches your res.send(status) before the database query has been resolved. My suggestion should work fine for you, but as your processes become more complex, I would look into promises to resolve any further async issues.

Related

How can I reduce this code duplication in NodeJS/Mongoose

I am using NodeJS and Mongoose for an application that has users. And I have a large number of actions the server does on a particular user, depending on the request.
That means, I have this particular code fragment appearing in a lot of functions:
User.findOne({'email':req.user.email}, function (err, user) {
if (err) {
console.log('err');
res.send('Error');
}
if(!user){
console.log('err');
res.send('Error');
}
// do something with returned user
user.data = ....
...
user.save(function(err) {
if(err) {
console.log('err');
res.send('Error');
}
else {
console.log('success');
res.send('Success');
}
}
As you can see, there is a lot of code that replicates. The code that changes is the part 'do something with returned user'. Almost everything else (error messages, etc.) remains same.
So, how can I extract this part out? Since this is working on callback mechanism, is there a certain way to achieve this?
One way is to use Promises. It would involve finding a way to convert the Mongooose api to return Promises instead of using callbacks. After that, you could create code that would follow the lines of
User.findOne(...)
.then((user) => {
// do something with the returned user
return user.save();
}).then(() => {
console.log('success');
res.send('Success');
}).catch(() => {
console.log('err');
res.send('Error');
});
Promises resemble traditional synchronous coding where you can propagate errors akin to try-catch block and thus needing only one error handling location. This way you wouldn't have to replicate the console.log('err'); res.send('Error'); lines in multiple places.
You can read an introduction to Promises for example in "Promises - A Gentle Introduction". For the part on converting Mongoose to Promises there may be an existing module for this, or another approach that APIs use is to not give callback function as the last argument and then a Promise is returned instead. Unfortunately, I don't have exact knowledge in this particular Mongoose API.

Sending different POST response in NodeJS

I would like to get some help with the following problem. I'm writing my bsc thesis, and this small part of code would be responsible for registering a user. (I'm new at nodejs actually). I'm using express and mongoose for this too.
I would like to process the request data, and check for some errors, first I would like to check if all fields exist, secondly if someone already registered with this e-mail address.
Based on the errors (or on success), I would like to send different responses. If a field is missing, then a 400 Bad request, if a user exists, then 409 Conflict, and 200 OK, if everything is ok. But I would only like to do the callback if there are no errors, but I'm kinda stuck here... I get the error Can't set headers after they are sent, which is obvious actually, because JS continues processing the code even if a response is set.
app.post('/register', function (req, res) {
var user = new User(req.body);
checkErrors(req, res, user, registerUser);
});
var registerUser = function(req, res, user){
user.save(function(err, user){
if (err) return console.log(err);
});
res.sendStatus(200);
};
var checkErrors = function(req, res, user, callback){
var properties = [ 'firstName', 'lastName', 'email', 'password', 'dateOfBirth' ];
for(var i = 0; i < properties.length; i++){
if(!req.body.hasOwnProperty(properties[i])){
res.status(400).send('field ' + properties[i] + ' not found');
}
}
var criteria = {
email: req.body.email
};
User.find(criteria).exec(function(err, user){
if(user.length > 0){
res.status(409).send('user already exists');
}
});
callback(req, res, user);
};
I think the problem is in the for loop in checkErrors. Since you call res.status(400).send() within the loop, you can end up calling it multiple times, which will trigger an error after the first call since a response will already have been sent back to the client.
Inside the loop, you can instead add missing fields to an array, then check the length of the array to see if you should respond with a 400 or continue. That way, you will only call res.status(400).send() one time.
For example:
...
var missingFields = [];
for(var i = 0; i < properties.length; i++){
if(!req.body.hasOwnProperty(properties[i])){
missingFields.push(properties[i]);
}
}
if(missingFields.length > 0) {
return res.status(400).send({"missingFields" : missingFields});
}
...
In general, I advise that you put return in front of each res.send() call, to ensure that no others are accidentally called later on.
An example of this is:
User.find(criteria).exec(function(err, user){
// We put return here in case you later add conditionals that are not
// mutually exclusive, since execution will continue past the
// res.status() call without return
if(user.length > 0){
return res.status(409).send('user already exists');
}
// Note that we also put this function call within the block of the
// User.find() callback, since it should not execute until
// User.find() completes and we can check for existing users.
return callback(req, res, user);
});
You probably noticed that I moved callback(req, res, user). If we leave callback(req, res, user) outside the body of the User.find() callback, it is possible that it will be executed before User.find() is completed. This is one of the gotchas of asynchronous programming with Node.js. Callback functions signal when a task is completed, so execution can be done "out of order" in relation to your source code if you don't wrap operations that you want to be sequential within callbacks.
On a side note, in the function registerUser, if user.save fails then the client will never know, since the function sends a 200 status code for any request. This happens for the same reason I mentioned above: because res.sendStatus(200) is not wrapped inside the user.save callback function, it may run before the save operation has completed. If an error occurs during a save, you should tell the client, probably with a 500 status code. For example:
var registerUser = function(req, res, user){
user.save(function(err, user){
if (err) {
console.error(err);
return res.status(500).send(err);
}
return res.sendStatus(201);
});
};
Your call to registerUser() is defined after the route and would be undefined since it's not a hoisted function.
Your use of scope in the closures isn't correct. For your specific error, it's because you're running res.send() in a loop when it's only supposed to be called once per request (hence already sent headers a.k.a. response already sent). You should be returning from the function directly after calling res.send() as well.

Node.js delete request

I have a node.js application with Express for routing and Mongoose for the database access.
I have this HTTP DELETE request that is deleting an entry in the database if certain requirements are met.
.delete(function (req, res) {
Movie.findOne({_id: req.params.id
}, function (err, movie) {
if (err)
res.send(err);
for (var i = 0, len = movie.actors.length; i < len; i++) {
if (movie.actors[i].actor == "Chuck Norris"){
res.status(403).send({ message: 'Cannot delete Chuck Norris' });
}
else {
Movie.remove({_id: req.params.id
}, function (err, movie) {
if (err)
res.send(err);
res.json({message: 'Movie deleted'});
});
}
}
});
});
If I send a HTTP DELETE with the ID of a film, it will check in the actors list if Chuck Norris is in the movie and I will prevent the deletion if he is there.
The problem is that my console is returning me this error :
Error: Can't set headers after they are sent.
So I presume that this an issue with my callbacks. Due to the asynchronus nature of node.js the "slow" database call made that my .delete sent the headers before the findOne finished ?
How can I manage to validate before deletion and send a proper http error code if the deletion is not possible ?
Be careful when you respond to a request multiple times in the same scope like that. On error you should prepend return to res.send(err) so that execution will not continue further. The same goes for your res.status() in the for-loop.

Testing NodeJs with Mocha/Sinon - Sails

I'm relatively new to nodejs and sailsjs framework, and I really enjoy write code with it, but coming from a PHP background I found testing nodeJs a bit weird.
I'm trying to test with mocha and sinon the method login of my AuthService, but being not expert I would need an example on how do you achieve a successful test for it , unfortunately documentation online is still a bit poor an example will be a lots useful thanks!
login: function(username,password,callback) {
User.findOneByUsername(username, function(err,user){
// If has some error
if (err) { return callback(err) }
// if the user is not found with that username
if (!user) { return callback(err,false); }
// if is found we match the password
bcrypt.compare(password, user.password, function (err, res) {
if (!res || err) return callback(err,false);
return callback(err,true,user);
});
});
}
If you can make light on this will be really appreciated
Check we.js example for how to setup you tests:
link: https://github.com/wejs/we-example/tree/master/test ( with only "headless browser" tests now )
For integration and unit tests with supertest check: https://github.com/wejs/we/tree/emberjsDev/tests

Express js res.redirect() from mongoose callback not working

What I'm trying to do here is,
from /expense/new page submitting POST request to /expense/newPost
on Expressjs, handling this way
app.post('/expense/newPost', function(req, res) { ...
continue, using mongoose I validate the collection as
tmpExp = new Expense(req.body);
tmpExp.validate(function(err) {
if(err || !isValidForm) {
req.session.form.errField = _.extend(req.session.form.errField, (err.errors || err ));
req.session.rePop = req.body;
res.redirect('/expense/new');
} else {
console.log('now saving') // successfully logs here.
tmpExp.save(expPost, function(err2, savedDoc) {
if(err2) {
req.session.flash = {
global: true
, css: "error"
, message: "Internal Server Error"
}
res.redirect('/expense/new');
} else {
res.redirect('/expense/new?success=' + savedDoc.bill_id);
}
});
}
});
for shake of clearity I removed some of the validation code.
Now the problem is, after submitting the POST request by browser data is successfully saved in mongodb but browser not redirect and just waiting for response from server
Your save callback is not passed in properly.
tmpExp.save(expPost, function(err2, savedDoc) {
should be:
tmpExp.save(function(err2, savedDoc) {
Assuming verification code is the only thing you stripped from this file, res is not defined. I'd suggest you just return Error or null and do the remaining logic in the parent function, where res is likely to be present. This also is generally a good practice because your model will be reusable (no path parts in the model)

Resources