DEV Community

Bentil Shadrack
Bentil Shadrack

Posted on • Edited on

How to write Custom Error Handler Middleware in Express.js using JavaScript 👩‍💻

What is Error Handler

Error handler is responsible of identifying and handling runtime issues.
Express.js comes pre-configured with a built-in Error Handler by default.

Error Handlers In ExpressJS🚀

Whenever a server error occurs, Express.js detects it and, unless you have a custom error handler, uses its built-in error handler to send a response to the client with the error message. Not only is Express.JS keen to handler errors properly but also to correctly empty away any unused resources when the application starts up again.

How to write Custom Error Handler Middleware in Express.js using JavaScript🚀

1. Create Custom ErrorHandler middleware

Folder Structure

// ErrorHandler.js
const ErrorHandler = (err, req, res, next) => {
    console.log("Middleware Error Hadnling");
    const errStatus = err.statusCode || 500;
    const errMsg = err.message || 'Something went wrong';
    res.status(errStatus).json({
        success: false,
        status: errStatus,
        message: errMsg,
        stack: process.env.NODE_ENV === 'development' ? err.stack : {}
    })
}

export default ErrorHandler
Enter fullscreen mode Exit fullscreen mode

NOTE: _ err.stack shows the exact file and line number the error occured. This is only needed in developement mode to debug your code. It becomes dangerous when your project structure is exposed on production_

2. Attach Custom Error Handler as The Last Middleware to Use

// index.js (Server Entery File)
import { AuthRoute, CategoryRoute, HomeRoute, PostRoute, UserRoute } from "./routes/index.routes.js";

import ErrorHandler from "./middlewares/ErrorHandler.js";


// init app
const app = express();


// MIDDLEWARES
app.use("/", HomeRoute);
app.use("/user", verifyAccessToken, UserRoute);
app.use("/categories", CategoryRoute);
app.use("/posts", PostRoute)
app.use("/auth", AuthRoute);

// ERROR HANDLER MIDDLEWARE (Last middleware to use)
app.use(ErrorHandler)

Enter fullscreen mode Exit fullscreen mode

3. How to Call the ErrorHandler

to call the ErrorHandler, Use the next() in Express.
The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.

app.use("/books", (req, res, next) => {
  try{
      // code block to be executed
  }catch(err){
    next(err);
  }
})
Enter fullscreen mode Exit fullscreen mode

Sample Error Response on Production

production error

Sample Error Response in developement✔

Developemnt error

Why Should I Create Custom ErrorHandler instead of using the built-in ErrorHandler👀

You might want to create a custom errorhandler for a number of reasons.
For instance, some projects don't set NODE_ENV to "production" during the production stages. If error is not handled correctly, this could result in the disclosure of sensitive information about the server.
Other projects needs different error object format be sent at different points.

As a developer, It is very important to handler all error correctly to avoid crushing your APP anytime an error occurs.

Bentil here🚀
If you like my content, you can support me here to keep up the work.👇

buy me a coffee

Let me know your questions or suggestions in the comment box below

Top comments (17)

Collapse
 
bbonsaye profile image
bbonsaye

Hey, thank you for this article. Do you mind sharing how your routes file is structured? The way mine is structured is that all the routes are on the router object and I export that route object and within app.js I have

app.use(authRoutes)
Enter fullscreen mode Exit fullscreen mode

I like how yours is explicit, I'm not sure how I can import each route by name the way you have it setup.
Thanks in advance.

Collapse
 
qbentil profile image
Bentil Shadrack

Project Structure

ps

Routes Structure:

rs

This is how each route looks like

er

For easy export and import, I have created the index.route.js to export all routes from a single file

ir

So I can easily import the routes like this

im
Instead of importing them from their separate files.

This is a typical backend repo of mine. You can check it out
github.com/qbentil/funchat-backend

Collapse
 
bbonsaye profile image
bbonsaye • Edited

Thank you for sharing that, I'm going to separate my routes like that too. If I may, I seen a video of someone who had a ".env" file in the root directory and a config folder located in "/src/config" and within that config.js file, they basically copied the variables in ".env" and pasted them in "config.js" and exported them to be used in their code.

Right now, I only have the ".env" file and access the variables located within it using the "process.env" object within my code, example: "process.env.HOST"

I like the idea of accessing the environment variables like so; "config.HOSTNAME" but, I find it redundant and time consuming to always update "/configs/config.js" every time we add a new variable to ".env"

Is that what you are doing or have you found a way where every time you add/remove a new variable in ".env" it automatically adds/removes the variable in "/configs/config.js"?

by the way, I just checked out your GitHub Portfolio briefly and noticed a minor typo. In your "ABOUT ME" you have "(Coud Storage)" I think you meant, "(Cloud Storage" -- tryna help hope that's not annoying to point out.

Thread Thread
 
qbentil profile image
Bentil Shadrack

I also use the same approach you are using now.
I access the env variables through the process.env.NAME

Thank you very much for the feedback on my readme. I really Appreciate.🥰🎉
I will check it out asap

Collapse
 
miguelznunez profile image
Miguel Z. Nunez

Can you show me how I would go about implementing this error handler with try catch in the following GET route? The route makes a query to a database table named images and sends the data over to the frontend. If there is some kind of error in accessing the data, I'm not sure how to go about grabbing the database error. I am using "throw new Error" but that only stops the program on its tracks. I want to be able to get the error in JSON and send the error to the user if possible.

app.get("/", (req, res) => {
dbConnection.query("SELECT * FROM images WHERE user_id = ?", [1], (err, result) => {
if(!err) res.render("index", {images:result})
else throw new Error(err)
})
})

Collapse
 
qbentil profile image
Bentil Shadrack

Hello Miguel, You can put it this way if you have your errorhandler middleware in place

app.get("/", (req, res, next) => {
    try {
        dbConnection.query("SELECT * FROM images WHERE user_id = ?", [1], (err, result) => {
            res.render("index", { images: result })
        })
    } catch (error) {
        next(error)
    }
})
Enter fullscreen mode Exit fullscreen mode

I hope this help☺

Collapse
 
javadsh profile image
javad-sh

Even if we don't use a try and catch and even if we don't use next(), the errors in the route are accessible in error handler middleware.
What is the reason for using the try and catch?
I would also be grateful if you could tell me how to customize the errors of each root in itself.I mean how to set for example error message and or name in every route.

Collapse
 
qbentil profile image
Bentil Shadrack

Without the next() The errors will not be handled by your error Handler middleware. It will be handled by Express framework’s default error handler

Errors that are created by asynchronous functions that are called from route handlers, need to be handled differently. The error from asynchronous functions are not handled by the default error handler in Express which can result in crashing the entire App. Putting then in a try catch block will help you handle those errors separately using you custom error handler

Collapse
 
yogeshyadav profile image
Yogesh Yadav

This was simple and straightforward. Thanks for sharing.

Collapse
 
qbentil profile image
Bentil Shadrack

I am glad you like it✨🚀

Collapse
 
ethel3 profile image
Ethel Akrasi Akosua

This piece was very helpful.

Collapse
 
qbentil profile image
Bentil Shadrack

Thank youu

Collapse
 
krishnacyber profile image
krishna-Tiwari

Hey, very very thank you for this article. This helps me a lot and finding you a good guy.. keep sharing and shining 🌟🌟

Collapse
 
qbentil profile image
Bentil Shadrack

Hey Krishna
Thank you for the positive feedback.
I'm glad you found this helpful🙌

Collapse
 
nanaole profile image
Offei Emmanuel

I will try it. N thanks to the creator of d content. You putting out priceless information for free..... 💯. Continue the good work.

Collapse
 
qbentil profile image
Bentil Shadrack

You are most welcome
I'm glad you like it