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

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));
});

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.

(node:3966) UnhandledPromiseRejectionWarning: Error: querySrv ECONNREFUSED

I'm trying to fix an error UnhandledPromiseRejectionWarning: Error: querySrv ECONNREFUSED when I make an axios call to fetch user data from mongoose query without internet connection. I've tried to wrap both the mongoose query User.findOne() and mongoose.connect() with try catch, but the error still remain.
(node:3966) UnhandledPromiseRejectionWarning: Error: querySrv
ECONNREFUSED _mongodb._tcp.cluster1-94jth.mongodb.net [0] at
QueryReqWrap.onresolve [as oncomplete] (dns.js:196:19) [0] (node:3966)
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) [0] (node:3966) [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.
FRONT-END
client.js
try {
const res = await axios.get('/auth/user?', {
params: {
refreshToken: refreshToken,
userID: userID
}
}
);
console.log(res.data);
} catch (error) {
if(error.toJSON().message === 'Network Error'){
alert('no internet connection');
}
}
BACK-END
auth.routes.js
auth.get(
'/user',
async(req, res)=>{
try {
const {userID, refreshToken, uniqueDeviceID, authTimestamp} = req.query;
const existingUser = await User.findOne({
$and: [
{'user_id': userID},
{'refresh_token': refreshToken}
]
});
res.send(existingUser);
} catch (error) {
console.log(error);
}
}
);
server.js
try {
mongoose.connect(keys.mongoURI, {useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true});
console.log('Database Connected');
} catch (error) {
console.log(error);
}
Wrapping mongoose.connect with try/catch will not work because its no doing async/await.
You should:
mongoose.connect(keys.mongoURI, {useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true})
.then(() => console.log('Database Connected'))
.catch(error=> console.log(error));
try/catch won't work with an asynchronous function without await
so to catch an error from asynchronous function:
try {
await someAsyncFunction();
} catch (e) {
//...
}
or you could use catch method from Promise or even use callbacks.

`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);
}
};

Getting an UnhandledPromiseRejectionWarning when posting to a NodeJS backend

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};

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