DEV Community

Dudi Nirgad
Dudi Nirgad

Posted on • Edited on

8 3

Express.js Async + Sync Global Exception Handler

Hi everyone, hope you all are doing ok in the COVID-19 world.
Recently I've been playing around with Express, and I needed to setup an error handler for my project.

I have been searching for a way to catch all exceptions in my project, something that will work both for sync and async routes.

To my surprise, I couldn't find an easy solution for it, so I had to come up with something of my own.

Let's walk it through:

first define your error handler
errorHandler.js:

const handleErrors = (err, req, res, next) => {
    if (res.headersSent) return next(err);

    // more handle error logic should be inserted here.

    res.status(500).json({
        msg: "Server Error",
    });

module.exports = handleErrors;

register your error handler (after all your routes)
server.js:

// Middlewares
app.use(cors());
app.use(express.json());
app.use(fileupload());
app.use(cookies());

// Routes
app.use("/", routes);
app.use(handleErrors); <------

Now we are going to do some javascript magic, we are going to leverage "express-async-handler" and write some of our own magic, to make the global exception handler work.

now we are going to hook express.Router which will return a new router that will have error handling for both async/sync routes

hookRouter.js

const express = require("express");
const originalRouterFunc = express.Router;
const asyncHandler = require("express-async-handler");

export function hookRouter() {
    function hookAllRouteMethods(router) {
        const methods = ["get", "post", "put", "delete", "options", "head", "all", "use"]; // all router methods
        methods.forEach(method => {
            const originalRouterFunc = router[method];
            const hookedRouterMethod = async function (path, ...routeHandlers) {
                routeHandlers = routeHandlers.map(f =>
                    asyncHandler(function (req, res, next) { // async error handler
                        // sync error handler start
                        try {
                            return f(req, res, next); // original route handler
                        } catch (e) {
                            console.log("hahah I caught you =)");
                            next(e, req, res); // pass exception to our error handler.
                        }
                        // sync error handler end
                    })
                );
                originalRouterFunc.apply(router, [path, ...routeHandlers]);
            };
            router[method] = hookedRouterMethod;
        });
    }

    function hookRouterCreation() {
        express.Router = function () {
            const router = originalRouterFunc.apply(this, arguments);
            hookAllRouteMethods(router);
            return router;
        };
    }
    hookRouterCreation();
}

next, we just have to hook our router at the top of server.js (or before you use routes):

const { hookRouter } = require("./hookRouter");
hookRouter();

That's it! now everytime you will use express.Router() it will have your error handler !

Hope this was helpful for you, Also this solution is still not 'battle tested' so I would like to hear what you guys think =).

Tiugo image

Fast, Lean, and Fully Extensible

CKEditor 5 is built for developers who value flexibility and speed. Pick the features that matter, drop the ones that don’t and enjoy a high-performance WYSIWYG that fits into your workflow

Start now

Top comments (0)

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay