I set up an error handler middleware in my backend to handle errors (duh) but it seems to not be doing what it's supposed to. As in every time there is an error, the app crashes and there's no proper response from the server. The way I understand it is that I am throwing a new error through my authController.js but I am never handling the exception made in server.js through errorHandlerMiddleware, therefore crashing the server. Can anyone explain to me what I am doing wrong? Thanks
Error Handler
const errorHandlerMiddleware = (err, req, res, next)=>{
console.log(err)
const defaultError = {
statusCode: err.statusCode || 500,
msg: err.message || "Something Went Wrong, Try Again Later",
}
if(err.name==="ValidationError"){
defaultError.statusCode = 400
defaultError.msg = Object.values(err.errors).map((item)=> item.message).join(', ')
}
if(err.code && err.code === 11000){
defaultError.statusCode = 400
defaultError.msg= `${Object.keys(err.keyValue)} has to be unique`
}
res.status(defaultError.statusCode).json({msg: defaultError.msg})
}
export default errorHandlerMiddleware
Server
import express from "express";
const app = express();
dotenv.config();
import notFound from "./middleware/NotFound.js";
import errorHandlerMiddleware from "./middleware/errorHandlerMiddleware.js";
import authRouter from "./routes/authRouter.js";
import dotenv from "dotenv";
import connectDB from "./db/connect.js";
app.use(express.json());
app.get("/", (req, res) => {
res.send("Welcome");
});
app.get("/api/v1", (req, res) => {
res.json({ msg: "API" });
});
app.use("/api/v1/auth", authRouter);
app.use(notFound);
app.use(errorHandlerMiddleware);
const port = process.env.PORT || 5000;
const start = async () => {
try {
await connectDB(process.env.MONGO_URL);
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
} catch (error) {
console.log(error);
}
};
start();
Auth Controller
import {BadRequestError, UnauthenticatedError} from "../errorPackage/index.js"
import User from '../models/User.js'
const register = async(req, res) =>{
const {name, email, password} = req.body
if(!name || !email || !password){
throw new BadRequestError("Please Provide All Values")
}
const alreadyUser = await User.findOne({email})
if(alreadyUser){
throw new BadRequestError("Email In Use")
}
const user = await User.create(req.body)
const token = user.createJWT()
res.json({
user:{
name: user.name,
email: user.email,
},
token,
})
console.log('register')
}
const login = async(req, res) =>{
const{email, password} = req.body
if(!email || !password){
throw new BadRequestError("Please Provide All Values")
}
const user = await User.findOne({email}).select(' password')
if(!user){
throw new UnauthenticatedError("Invalid Email")
}
const passwordMatch = await user.comparePassword(password)
if(!passwordMatch){
throw new UnauthenticatedError("Invalid Credentials")
}
const token = await user.createJWT()
user.password = undefined;
res.status(200).json({user, token})
console.log('login success')
}
const updateUser = async(req, res) =>{
res.send('Update')
}
export {register, login, updateUser}
authRouter
import express from "express";
const router = express.Router()
import { register, login, updateUser} from "../controllers/authController.js";
router.route('/register').post(register)
router.route('/login').post(login)
router.route('/updateUser').patch(updateUser)
export default router
An example of an error would be sending a post request through register with an already in-use email, it would look something like this
[0] Server is running on port 5000
[0] file:///C:/Users/Bharat/Desktop/MERNPrj/controllers/authController.js:10
[0] throw new BadRequestError("Email In Use")
[0] ^
[0]
[0] BadRequestError: Email In Use
[0] at register (file:///C:/Users/Bharat/Desktop/MERNPrj/controllers/authController.js:10:15)
[0] at processTicksAndRejections (node:internal/process/task_queues:96:5) {
[0] statusCode: 400
[0] }
[0] [nodemon] app crashed - waiting for file changes before starting...
What I can surmise from this is that the app is crashing before the server has a chance to respond with the proper error reponse
CodePudding user response:
I guess you forgot to wrap your code inside a try-catch
block. Since you are throwing an error, but it is never caught to be handled.
const register = async(req, res,next) =>{ //add next to pass your error to the Error handling middleware
const {name, email, password} = req.body
try {
if(!name || !email || !password){
throw new BadRequestError("Please Provide All Values")
}
const alreadyUser = await User.findOne({email})
if(alreadyUser){
throw new BadRequestError("Email In Use")
}
const user = await User.create(req.body)
const token = user.createJWT()
res.json({
user:{
name: user.name,
email: user.email,
},
token,
})
console.log('register')
//I don't think the logging will work since you already sent the response, so the above console.log is not a reachable code.
} catch (error) {
next(error) //This will pass your thrown error to the next middleware which is the Error Handling middleware
}
}
Yeah and inside the Server
the Error Handling middleware should be the last middleware, and it should be after the authController
as well. I am not sure what is the notFound
middleware. But I guess it should be like this in order to pass the error to the ErrorHandling middleware directly.
app.use("/api/v1/auth", authRouter);
app.use(errorHandlerMiddleware);