Getting an UnhandledPromiseRejectionWarning when posting to a NodeJS backend - node.js

Need a little help. Been learning NodeJS. And so far so good. But I am running into an issue when I try to create a new ToDo object that's associated with an authenticated user.
I get the following error
(node:54162) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:54162) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Here is the offending code:
app.post('/todos', authenticate, (req, res) => {
var todo = new Todo({
text: req.body.text,
_creator: req.user._id
});
todo.save().then(() => {
res.send(todo);
}).catch((e) => {
res.status(400).send(e);
});
})
I am not sure what I am missing. I've read in certain places about try catch mismatches. But I am still not sure.
Just for more context, I have also added my authenticate.js
var {User} = require('./../models/user');
//Definining endpoint authentication middleware
var authenticate = (req, res, next) => {
var token = req.header('x-auth');
User.findByToken(token).then((user) => {
if(!user) {
return Promise.reject();
}
req.user = user;
req.token = token;
next();
res.send(user);
}).catch((e) => {
res.status(401).send();
});
};
module.exports = {authenticate};

Related

node.js async multiple await not working for user signup

I am trying to reproduce this code using async/await but I can't figure how to
.then.catch chain/nest
exports.signup = (req, res, next) => {
bcrypt.hash(req.body.password, 10)
.then(hash => {
const user = new User({
email: req.body.email,
password: hash
});
user.save()
.then(() => res.status(201).json({ message: 'Utilisateur créé !' }))
.catch(error => res.status(400).json({ error }));
})
.catch(error => res.status(500).json({ error }));
};
What I came up with trying to use async/await
exports.signup = async (req, res, next) => {
try {
const hash = await bcrypt.hash(req.body.password, 10);
const user = new User({
email: req.body.email,
password: hash
});
console.log(user);
let saveUser = await user.save();
console.log(saveUser);
res.status(201).json({ message: 'Utilisateur créé !'})
} catch (e) {
res.status(500).json({e})
}
};
I am getting the user in my console but the code crashes during user.save() since I don't get anything from console.log(saveUser)
I've been reading that you can stack await functions into one try block, but maybe here it doesn't work since you need
I've tried separating the try/catch, requiring me to initialise hash outside of the try block since i'll be using it in the second try but it's also not working.
After editing according to Nil Alfasir's thoughts:
exports.signup = async (req, res, next) => {
try {
const hash = await bcrypt.hash(req.body.password, 10);
const user = new User({
email: req.body.email,
password: hash
});
console.log(user);
user.save();
return res.status(201).json({ message: 'Utilisateur créé !'})
} catch (e) {
return res.status(500).json({e})
}
};
But I'm getting this in the console
(node:43390) UnhandledPromiseRejectionWarning: MongoError: E11000 duplicate key error collection: myFirstDatabase.users index: username_1 dup key: { username: null }
.
.
.
(node:43390) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:43390) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Correcting Nir Alfasi on save async
save() IS a async function SAVE ASYNC
so it won't return anything.
If there's an error it can be caught be catch.
A few issues:
user.save() doesn't return any value (according to the first snippet) - and you're trying to save a returned value into saveUser
Nit: please add a return before res.status...
UPDATE
The "update" of the question totally changed it, please avoid from doing that and post a new question in the future.
Sounds like you must provide a username when creating a user because username must be unique, and when you try to create multiple users without a username the DB creates a record with username=null so the first one may create but the second one will fail.

Async/await mvc express problems handling errors with .catch()

I'm trying to handle errors using express middleware, with these lines I have the following errors
user.js controller
app.post('/create', async (req, res, next) => {
const data = await User.create(req.body)
.catch((err) => next(err));
res.status(201).json({ ok: true, ...data });
});
user.js model
UserSchema.statics.create = async function createUser(data) {
delete data.role;
const user = await new this(data).save();
return { token: user.newToken(), user };
};
app.js
app.use((err, req, res, next) => {
res.status(err.code || 400);
res.json({ ok: false, err: err.message });
});
Errors
(node:3304) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
...
(node:3304) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 9)
(node:3304) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
After to proof with try/catch in the user.js controller i don't have any error, but in the express documentation use try/catch is not recommended.
app.post('/create', async (req, res, next) => {
try {
const data = await User.create(req.body)
res.status(201).json({ ok: true, ...data });
} catch (err) {
next(err);
}
});
Any ideas?
You either use await or then/catch:
app.post('/create', async (req, res, next) => {
User.create(req.body)
.then(data => {
res.status(201).json({ ok: true, ...data });
})
.catch((err) => next(err));
});

`UnhandledPromiseRejectionWarning: Unhandled promise rejection` in my node application

For learning Node.js I follow a course where they use a async/await like this:
exports.signup = async (req, res) => {
const userExists = await userExists.findOne({ email: req.body.email });
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = await new User(req.body);
await user.save();
return res.status(200).json({ user });
}
};
But it gives me a UnhandledPromiseRejectionWarning with crashing the application.
(node:10780) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise
which was not handled with .catch(). (rejection id: 1)
(node:10780) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero
exit code.
It seems I didn't handle the error part but I did it with my else block, isn't it working like this?
Any help will be appreciated.
You need to catch any rejected promise from await statements by surrounding it with try/catch.
exports.signup = async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email });
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = new User(req.body);
await user.save();
return res.status(200).json({ user });
}
} catch(e) {
// some sort of internal error (probably database issue)
console.log(e);
res.sendStatus(500);
}
};
This also removes the await in await new User(req.body) as await only does something useful when you await a promise and new User() is not asynchronous and does not return a promise so there's no reason to use await with it.
Note, that to avoid a race condition where two separate requests might both find that the user doesn't exist and both requests may try to create one, you need to make sure that your user email is configured in the database as a unique key so you can never get duplicate users for the same email. This is a subtlety in server programming that is important to understand to avoid race conditions.
As #jfriend00 said You need to catch any rejected promise from await statements by surrounding it with try/catch. You get ReferenceError because of using userExists before it creates. I am pretty sure that it should be User as you named your Schema User const user = new User(req.body); Let me know if you have any issue after change the code:
exports.signup = async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email }); //I changed it to the Schema name
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = new User(req.body);
await user.save();
return res.status(200).json({ user });
}
} catch(e) {
// some sort of internal error (probably database issue)
console.log(e);
res.sendStatus(500);
}
};

I have an error in my registration routes

During the course of testing if my user's registration route is working fine using postman as a testing machine, it throw an error that I don't know what it means.
I have tried using an async function to catch the error, but it didn't work out
const express = require('express');
const router = express.Router();
// Use to help set a default image for users
const gravatar = require('gravatar');
// Use to encrypt our password from bringing plain text
const bcrypt = require('bcryptjs');
// I add the user model from my model
// So i can be able to check create a new registration
// and also check if email exist
const User = require('../../models/User');
// #route GET api/users/register
// #desc Register user
// #access Public
router.post('/register', (req, res) => {
User.findOne({ email: req.body.email }).then(user => {
if (user) {
errors.email = 'Email already exists';
return res.status(400).json(errors);
} else {
const avatar = gravatar.url(req.body.email, {
s: '200', // Size
r: 'pg', // Rating
d: 'mm' // Default
});
const newUser = new User({
name: req.body.name,
email: req.body.email,
avatar,
password: req.body.password
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(user => res.json(user))
.catch(err => console.log(err));
});
});
}
});
});
module.exports = router;
I want the user input on postman should be able to post the form so I can know if the route is actually working fine. And this is the error I got on my console
(node:14164) UnhandledPromiseRejectionWarning: ReferenceError: errors is not defined
at User.findOne.then.user (the working director/name.js:26:7)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:14164) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:14164) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Normally we should handle the error in a kind of this way:
User.findOne({ email: req.body.email }).then(user => {
// ...
}).catch(error => {
console.log('error', error)
res.json({error: error})
})

Redux action req.body undefined for express route

I've been struggling with this feature that's supposed to send redux-form values to my express server and awaiting mongoose model.
The request body once reached the express route doesn't contain the form values that I've sent in the redux-action. The form values are properly console.logged on the client-side (inside the submitInvestment action). Though, once sent to express (using axios) -> console logging the req.body shows undefined
form.js
<form onSubmit={this.props.handleSubmit((values) => { this.props.submitInvestment(values) })}>
export default connect(null, actions)(reduxForm({ form: 'investmentForm' })(InvestmentForm))
actions.js
export const submitInvestment = (values) => async dispatch => {
console.log('before request')
console.log(values)
const res = await axios.post('/api/investments', values);
console.log('after request', res.data)
// dispatch({ type: FETCH_USER, payload: res.data });
};
route.js
module.exports = app => {
app.post('/api/investments', async (req, res) => {
console.log(req.body)
res.sendStatus(200);
});
}
on form submission (console.log browser)
+ server logs an undefined req.body
Additionally; when I attempt to catch the request with the fully built route.js
module.exports = app => {
app.post('/api/investments', async (req, res) => {
const { currency, units, date } = req.body;
const investment = new Investment({
currency,
units,
date,
_user: req.user.id
});
try {
await investment.save();
res.status(200);
} catch (err) {
res.status(422).send(err);
}
});
}
then my server logs are
[0] (node:25154) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot match against 'undefined' or 'null'.
[0] (node:25154) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
The incoming request needs to be handled by the body parser middleware
App.js
app.use(bodyParser.json());

Resources