exit block of code with express and node - javascript

Here is my code
// on all routes that end with "users", do the following
router.route('/users')
.post(function(req, res, next) {
var user = new User();
user.username = req.body.username;
user.password = req.body.password;
User.find({username : user.username}, function(err, results){
if (results.length > 0) {
//if (err) res.send(err);
console.log('User exists: ', user.username);
res.send('User exists');
next();
}
});
user.save(function(err) {
if (err)
res.send(err);
res.json({
message: 'Created user.',
username: req.body.username,
password: req.body.password
});
});
})
User is just a Mongoose schema.
If the username is found in that first callback, I want to send a basic response of "User Exists", then exit. Right now I get an error because it moves on to the user.save bit and tries to write more info to the response which has already ended.
How can I exit the User.find block and the .post block altogether? In a normal C-like language I'd simply do return; but doing so only exits just the User.find block.
Thanks for any help

Try to write another case in else condition and return the callback like this
router.route('/users')
.post(function(req, res, next) {
var user = new User();
user.username = req.body.username;
user.password = req.body.password;
User.find({username : user.username}, function(err, results){
if (results.length > 0) {
//if (err) res.send(err);
console.log('User exists: ', user.username);
res.send('User exists');
return next();
}else{
user.save(function(err) {
if (err)
return res.send(err);
return res.json({
message: 'Created user.',
username: req.body.username,
password: req.body.password
});
});
}
});
})

In your current implementation, if it finds the user, it will run whatever you have written in your callback. You happen to have next() inside your callback. next() will exit this route and find the next route that would match. That means whatever you wrote under, won't be executed (I'm talking about the user.save part.
Anyways, to answer your question, if you want it to exit the User.find block and the .post all together, then just put the next() method below and outside your if statement.
I hope this helps.

Related

Node.js check if user already exists

Hello guys I am trying to check if a user already exists in the database, I have managed to stop creating a user if one already exists with the same name, however I do not seem to get the error message displayed. I am not too sure why my error is not being handled correctly. Here is my code:
// Register User
router.post('/register', function(req, res){
var name = req.body.name;
var email = req.body.email;
var username = req.body.username;
var password = req.body.password;
var password2 = req.body.password2;
//Validation
req.checkBody('name', 'Name is required').notEmpty();
req.checkBody('email', 'Email is required').notEmpty();
req.checkBody('email', 'Email is not valid').isEmail();
req.checkBody('username', 'Username is required').notEmpty();
req.checkBody('password', 'Password is required').notEmpty();
req.checkBody('password2', 'Passwords do not match').equals(req.body.password);
var errors = req.validationErrors();
if(errors){
res.render('register',{
errors:errors
});
}else{var newUser = new User({
name: name,
email:email,
username: username,
password: password
});
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(user){
return new Error('User already exists!');
}else{
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
}
});
req.flash('success_msg', 'You are registered and can now login');
res.redirect('/users/login');
}
});
This will work exactly as you wish.I had the same issue trying to make it work and I assure you it does. Cheers!
User.getUserByUsername(username, function(err, user){ //must check if user exists
if(err) throw err;
if(user){
console.log('existing...'); //may be deleted
req.flash('error_msg', 'This username already exists');
res.redirect('/users/register');
} else {
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);//may be deleted
});
req.flash('success_msg', 'You registered successfuly and you can now login');
res.redirect('/users/login');
}
})
Two things I see wrong:
You're doing synchronous operations after passing off the control to an asynchronous callback
You're not doing anything useful with the errors inside your asynchronous callback
Here the asynchronous callback is the function you pass to User.getUserByUsername
router.post('/register', function(req, res) {
...
User.getUserByUsername(username, function(err, user) {
// Any errors get thrown here need to be dealt with here
// Also you can't simply "throw" or "return" errors from this,
// You need to use Express's "next" method to handle these errors
})
// And since you've gone asynchronous above (User.getUserByUsername)
// you can't do the following here:
req.flash('success_msg', 'You are registered and can now login')
res.redirect('/users/login')
// otherwise these will ALWAYS get executed,
// regardless of what the result of `User.getUserByUsername` may be
})
You need to do something like this:
router.post('/register', function(req, res, next) { // use `next` to handle errors
...
User.getUserByUsername(username, function(err, user) {
if (err) {
next(err)
} else if (user) {
next(new Error('User already exists!'))
} else {
req.flash('success_msg', 'You are registered and can now login')
res.redirect('/users/login')
}
})
})
PS: Also you're not saving newUser (at least not in the code you've posted)
If you only want to check if user with given username exist or not, then I have used this simple trick.
What I am doing is while registering, if some error occurs then I am checking if this error is UserExistError(which is related to mongodb, and you can see it when it occurs in terminal)
If err is equal to UserExistError then I am rendering an alert which is in separate file.
register(new User({username:req.body.username}),req.body.password,function(err,user){
if(err)
{ var chk=1;
console.log(err);
if(err=='UserExistsError');
console.log("error is here");
return res.render("register",{chk:chk});
}
passport.authenticate("local")(req,res,function(){
res.redirect("/dashboard");
})
});
var candidateName = username;
var queryforUsername = {};
queryforUsername['username'] = candidateName;
User.find(queryforUsername, function(err, item){
if(err) throw (err);
if(item.length > 0){
req.flash('error_msg', 'User with username '+username+' already exists!');
res.redirect('register');
}else if(item.length == 0){
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
req.flash('success_msg', 'You are registered and can now login');
res.redirect('/users/login');
});
}
});
const { usuario } = req.body;
let user = await User.findOne({ usuario});
if (user) {
return res.status(400).json({ ok: false, msg: 'El usuario ya existe' });
}
//crear nuevo user
user = new User(req.body);

Nodejs/Express - Error: Can't set headers after they are sent

Pretty new to node/express. I'm checking to see if the user (via the username) already exists in the database that one wants to register to, giving an error if they do already exist.
When I use curl to try to set it off intentionally, I get the following error:
Error: Can't set headers after they are sent.
I know already that the first check I do to ensure that all the fields are filled in works correctly, and provides no issues with headers being set multiple times.
Any help would be greatly appreciated.
(My relevant code is below. If you need anything else, feel free to say so!)
router.post('/register', function(req, res, next) {
if(!req.body.username || !req.body.password){
return res.status(400).json({ message: 'Please fill out all fields.' });
}
User.count({ username: req.body.username}, function(err, count){
console.log(count);
if(count > 0) {
return res.status(400).json({message: 'This user already exists!' });
}
});
var user = new User();
user.username = req.body.username;
user.setPassword(req.body.password);
user.save(function(err) {
if(err) { return next(err); }
return res.json({ token: user.generateJWT()});
});
});
When you are returning inside User.count and user.save, you are returning only from inside the callbacks but not the entire method.
Its a good practice to send a response in just one place. At the end of the method. Before that evaluate your conditions and set the response code and response message in some variable. Which you can use to send the response as a final step.
Try this as a workaround for now:
router.post('/register', function(req, res, next)
{
if(!req.body.username || !req.body.password)
{
return res.status(400).json({ message: 'Please fill out all fields.' });
}
User.count({ username: req.body.username}, function(err, count)
{
console.log(count);
if(count > 0)
{
return res.status(400).json({message: 'This user already exists!' });
}
else
{
var user = new User();
user.username = req.body.username;
user.setPassword(req.body.password);
user.save(function(err)
{
if(err)
{
return next(err);
}
return res.json({ token: user.generateJWT()});
});
}
});
});
Put all your code in the callback function of User.count, otherwise the two part of code are executed
router.post('/register', function(req, res, next) {
if(!req.body.username || !req.body.password){
return res.status(400).json({ message: 'Please fill out all fields.' });
}
User.count({ username: req.body.username}, function(err, count){
console.log(count);
if(count > 0) {
return res.status(400).json({message: 'This user already exists!' });
}
var user = new User();
user.username = req.body.username;
user.setPassword(req.body.password);
user.save(function(err) {
if(err) { return next(err); }
return res.json({ token: user.generateJWT()});
});
});
});

Unexpected results with MongooseJS findOne()

Using Mongoose as an ODM with NodeJS, but not fully understanding how the error handling works. It works, but doesn't look right, and isn't in line with the documentation, so I'm worried that going down this road will haunt me later on.
For example, here is a basic signin route:
app.post('/signin', function(req, res){
var email = req.body.email;
var password = req.body.password;
mongoose.model('User').findOne({
email: email,
password: password
}, function(err, user){
if (err){
console.log('Database Error')
return res.json({error: 'Database Error'})
} else {
if (!user) {
console.log('User not found.');
return res.json({error: 'Email and/or password incorrect.'})
} else {
console.log('User ' + user.email + ' found. Logging in.');
res.json({
token: jwt.sign({}, 'top-secret', {subject: user}),
data: data[user]
})
}
}
})
})
I'm especially worried about:
if (err) {
//do something
} else {
if (!user){
//do something else
} else {
//log the user in
}
}
Haven't really used Mongo before today, but this feels like a lot of conditional error handling. Is there something that I'm not understanding properly here?
Was going to post as a comment but it was easier to paste this as an answer..
You can simplify the if-else nesting since you are returning at the end of each conditional, like so:
app.post('/signin', function (req, res) {
var email = req.body.email;
var password = req.body.password;
mongoose.model('User').findOne({
email: email,
password: password
}, function (err, user) {
if (err) {
console.log('Database Error');
return res.json({error: 'Database Error'});
}
if (!user) {
console.log('User not found.');
return res.json({error: 'Email and/or password incorrect.'});
}
console.log('User ' + user.email + ' found. Logging in.');
res.json({
token: jwt.sign({}, 'top-secret', {subject: user}),
data: data[user]
});
});
});

Error: Can't set headers after they are sent in Node / Express

I'm doing a tutorial in the MEAN Machine book, chapter about route APIs.
Full code posted here: https://gist.github.com/leongaban/6db44e513db4ca9e784f
The following code is the API to get all users, and then to get a user by a certain id.
Get all users:
// api/users
apiRouter.route('/users')
// create a user (accessed at POST http://localhost:8615/api/users)
.post(function(req, res) {
// create a new instance of the User model
var user = new User();
// set the users information (comes from the request)
user.name = req.body.name;
user.username = req.body.username;
user.password = req.body.password;
// save the user and check for errors
user.save(function(err) {
if (err) {
// duplicate entry
if (err.code == 11000)
return res.json({ success: false, message: 'A user with that username already exists. '});
else
return res.send(err);
}
// return a message
res.json({ message: 'User created!' });
});
})
// get all users (access at GET http://localhost:8615/api/users)
.get(function(req, res) {
User.find(function(err, users) {
if (err) return res.send(err);
// return the users
res.json(users);
})
});
Follow the above is the code to get just 1 user based on id:
// api/users/:user_id
apiRouter.route('/users/:user_id')
// get the user with that id
// (accessed at GET http://localhost:8615/api/users/:user_id)
.get(function(req, res) {
User.findById(req.params.user_id, function(err, user) {
if (err) return res.send(err);
// return that user
res.json(user);
})
// update the user with this id
.put(function(req, res) {
// use our user model to find the user we want
User.findById(req.params.user_id, function (err, user) {
if (err) return res.send(err);
// update the users info only if its new
if (req.body.name) user.name = req.body.name;
if (req.body.username) user.username = req.body.username;
if (req.body.password) user.password = req.body.password;
// save the user
user.save(function(err) {
if (err) return res.send(err);
// return a message
res.json({ message: 'User updated!' });
});
})
})
// delete the user with this id
.delete(function(req, res) {
User.remove({
_id: req.params.user_id
}, function(err, user) {
if (err) return res.send(err);
res.json({ message: 'Successfully deleted' });
});
});
});
Now going to my localhost:8615/api/users/ I am able to get all the users back
I then select an id from one of the users, for example:
localhost:8615/api/users/54b64c770dedef7c1a7d2c8b
And I get the following error:
TypeError: Object #<Query> has no method 'put'
at adminRouter.param.req.name (/Users/leongaban/NodeDallas/projects/awesome- test/server.js:110:3)
at Layer.handle [as handle_request] (/Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/layer.js:82:5)
at next (/Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/route.js:100:13)
at Route.dispatch (/Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/route.js:81:3)
at Layer.handle [as handle_request] (/Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/layer.js:82:5)
at /Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/index.js:233:24
at param (/Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/index.js:330:14)
at param (/Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/index.js:346:14)
at Function.proto.process_params (/Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/index.js:390:3)
at /Users/leongaban/NodeDallas/projects/awesome-test/node_modules/express/lib/router/index.js:227:12
In my Gist you can see that my headers are set once at the top:
https://gist.github.com/leongaban/6db44e513db4ca9e784f
Any idea why I'm having this problem?
You are missing the closing }) for the .get() method. So put is being called on the return of User.findById() It should be
.get(function(req, res) {
User.findById(req.params.user_id, function(err, user) {
if (err) return res.send(err);
// return that user
res.json(user);
})
}) // <-- was missing
// update the user with this id
.put(function(req, res) {

expressJS + MongoDB - login/register method

I want to have login/register function in my expressJS API.
So now im just inserting password and email into my database, i want this function to first check if user with this email is already in database - if yes, send response that user is logged.
If not, just insert him to database.
Is it possible to handle some errors in here?
I already have it:
exports.login = function(req, res){
var email = req.body.email;
var pwd = req.body.pass;
db.collection('users', function(err, collection) {
collection.insert({login:email, password: pwd}, {safe:true}, function(err, result) {
res.send("OK");
});
});
};\
and dont know what's next.
You can first try to find the user in your database. Assuming email is unique;
exports.login = function(req, res){
var email = req.body.email;
var pwd = req.body.pass;
db.collection('users', function(err, collection) {
if (err) return res.send(500, err);
collection.findOne({login:email}, function(err, user) {
// we found a user so respond back accordingly
if (user) return res.send('user logged in');
collection.insert({login:email, password: pwd}, {safe:true}, function(err, result) {
if (err) return res.send(500, err);
res.send("OK");
});
});
});
};
notice the return's before the res.send calls when handling errors.

Categories