Home > Software design >  Why does my app keep crashing through a faulty error handler in nodejs
Why does my app keep crashing through a faulty error handler in nodejs

Time:07-30

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);
  • Related