I have the following route setup in my node js api app:
const { body } = require("express-validator");
router.post(
"/user/signup",
[
body("firstName").not().isEmpty().withMessage("First name is required"),
body("lastName").not().isEmpty().withMessage("Last name is required"),
body("email")
.isEmail()
.withMessage("Email is required")
.custom((value, { req }) => {
return User.findOne({ email: value }).then(userDoc => {
if (userDoc) {
return Promise.reject('E-Mail address already exists!');
}
});
}),
body("mobile").not().isEmpty().withMessage("Mobile is required"),
body("password").not().isEmpty().withMessage("Password is required"),
body("confirmPassword")
.not()
.isEmpty()
.withMessage("Confirm password is required"),
],
UserController.signup
);
signup
method in UserController
const { validationResult } = require("express-validator");
exports.signup = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error('Validation failed.');
error.statusCode = 422;
error.data = errors.array();
throw error;
}
const {
firstName,
lastName,
email,
mobile,
password,
confirmPassword
} = req.body;
try {
if (password !== confirmPassword) {
res
.status(422)
.json({ message: "Password and confirm password must be same" });
}
//save user and return response to front end
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};
Code block at the end of app.js
to catch error:
/** Catch and return custom errors */
app.use((error, req, res, next) => {
const status = error.statusCode || 500;
const message = error.message;
const data = error.data;
res.status(status).json({ message: message, data: data });
});
In this route I'm checking if user has already registered with same email or not. If user has been registered with same email return error message.
Error message returned by server before crash:
/storage/node/Jeevan-Api/controllers/UserController.js:10
const error = new Error('Validation failed.'); ^
Error: Validation failed.
at exports.signup (/storage/node/Jeevan-Api/controllers/UserController.js:10:19)
at Layer.handle [as handle_request] (/storage/node/Jeevan-Api/node_modules/express/lib/router/layer.js:95:5)
at next (/storage/node/Jeevan-Api/node_modules/express/lib/router/route.js:144:13)
at middleware (/storage/node/Jeevan-Api/node_modules/express-validator/src/middlewares/check.js:16:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
statusCode: 422,
data: [
{
value: '[email protected]',
msg: 'E-Mail address already exists!',
param: 'email',
location: 'body'
}
]
}
[nodemon] app crashed - waiting for file changes before starting...
The above code does the job but the server crashes after it returns the error message. This is happening in both local server and my development server.
How can I return validation message and
CodePudding user response:
You are throwing error which makes the app to stop processing to the next request or response / middleware. What you could do is doing next(error)
so it will catch in the last catch
block.
Or you could also look into this to set up error handling in express; https://expressjs.com/en/guide/error-handling.html#:~:text=Writing error handlers
CodePudding user response:
This is happening because your middleware is throwing an async error
and your node app has no way of handling it.
Even if you have an error handler in place you need to explicitly call the next function with the error
object.
E.g.
try{
// Your code...
}catch(error){
console.log(error)
next(error)
}
When express sees next(error)
i.e. next function being called with an argument it passes it to the error handler that you have written at the end of app.js
/** Catch and return custom errors */
app.use((error, req, res, next) => {
const status = error.statusCode || 500;
const message = error.message;
const data = error.data;
res.status(status).json({ message: message, data: data });
});
Solution:
You can make use of an npm package express-async-errors
Link for the npm package: https://www.npmjs.com/package/express-async-errors
And in your app.js
file just add require('express-async-errors')
on the very top. This will direct all the async errors to the error handler middleware in your application.