DEV Community

Cover image for A simple way to handle errors in Express.js
Anderson. J
Anderson. J

Posted on

4 1

A simple way to handle errors in Express.js

Exists many ways to handle Errors in Express. A common way to do it it's using the default express middleware.

app.use(function(err, req, res, next) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
}
Enter fullscreen mode Exit fullscreen mode

Another way could be to handle errors inside of controllers.

router.get("/users", async (req, res) => {
    try {
        const users = await User.getAll();
    }
    catch(err) {
        return res.status(500).json({
            message: "Something broke!",
        });
    }

    res.status(200).json({
        message: "success",
        data: users,
    });
})
Enter fullscreen mode Exit fullscreen mode

That handling way could cause some problems to keep the code clean. This problem becomes more evident when we have many controllers or some functions like the next example:

router.get("/profile", async (req, res) => {
    try {
        const {username} = await User.auth();
        const preferences = await User.getPreferences(username);
    }
    catch(err) {
        if(err instance of AuthError) {
            return res.status(401).json({
                message: "Unauthorized",
            });
        }
        else {
            return res.status(500).json({
                message: "Something Broke!",
            });
        }
    }

    res.status(200).json({
        message: "success",
        data: users,
    });
});

Enter fullscreen mode Exit fullscreen mode

We can see how the code becomes less readable because of try/catch blocks. If we have other routes where we need to call similar functions we will be repeating code, and that's not ideal.

A simple solution.

A simple solution for this problem is using a wrapper that contains the controller function and letting the wrapper handle the exception.
The wrapper looks like this:

const errorHandlerWrapper = (promiseCallBack) => {
  return async (req, res, next) => {
    try {
      await promiseCallBack(req, res, next);
    } catch (err) {
      if (err instanceof AuthError) {
        res.status(401).json({
          message: "Unauthorized",
        });
      } 
      else {
        console.log(err);
        res.status(500).json({
          message: "Something Broke!",
        });
      }
    }
  };
};
Enter fullscreen mode Exit fullscreen mode

errorHandlerWrapper receives a controller used as a callback. Then, it returns a function that executes the callback inside a try/catch block.

In that way, we delegate error handling outside of controllers.

After refactoring the code, it looks like this:

router.get("/profile", errorHandlerWrapper(async (req, res) => {
    const {username} = await User.auth();
    const preferences = await User.getPreferences(username);

    res.status(200).json({
        message: "success",
        data: users,
    });
}));
Enter fullscreen mode Exit fullscreen mode

Note how the code reduced and became more readable. All this while we are still effectively handling errors.

Conclusion

It's important to keep route controllers readable. When the code begins to grow, keeping controllers clean could become a challenge. Implementing an alternative to repetitive code blocks it's the first step to face it.

If you know alternative ways to handle exceptions within controllers, let me know in the comments ✌

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay