Home > Software engineering >  How to handle specific errors with expressjs?
How to handle specific errors with expressjs?

Time:06-26

So I need to handle the http errors 500, 404, 401 and 403 plus every other error needs to return the 404 status code. So far I've tried with a switch case but it doesn't seem to work.

I could get it to work with a single error but adding multiple arrors breaks even that single one. In case you were wondering yes, i did read the docs but it talks about single error handling and i really need a way to catch them globally so that i don't have to put a middleware in every single request

Any help would be appreciated

import express from 'express';
import 'dotenv/config';

//import atlasConnection from './database/mongo-connection.js';
//import erroHandler from './middlewares/error.middleware.js';
//await atlasConnection();

const port = process.env.PORT;
const app = express();

// app.use(posts);
// app.use(users);

if (process.env.NODE_ENV !== 'test') {
  app.listen(port, () => console.log(`Server listening on port ${port}`));
}

app.get('/api', (req, res, next) => {
  res.send('test')
})

app.use(app.router)

app.use(function(err, req, res, next ) {

  switch (err.status) {
    case 500:
      res.status(500).json({
        "success": false,
        "code": 4001,
        "error": "Server Error"
      });
      break;
    case 404:
      res.status(404).json({
        "success": false,
        "code": 4001,
        "error": "Resource not found"
      });
      break;
    case 401:
      res.status(401).json({
        "success": false,
        "code": 2001,
        "error": "Unauthorized"
      });
      break;
    case 403:
      res.status(403).json({
        "success": false,
        "code": 2002,
        "error": "Forbidden"
      });
      break;

    default:
      res.status(404).json({
        "success": false,
        "code": 4001,
        "error": "Resource not found"
      });
      break;
  }

  next(err)

})
export default app;

How can i make it work?

CodePudding user response:

Several issues I see:

  1. What you have should work if someone calls next(err) and err is an object with err.status set appropriately. But, that is not a default thing that happens anywhere so that would only work if your own route handlers are doing that.

  2. You don't show any 404 error handler which is typically a regular middleware as the last middleware as shown here in the doc. So, nothing you show will cause a 404 when no route matches the request.

  3. You should not be calling next(err) in your error handler. You've already sent a response in your error handler. No further routing or error handling should be done for this request.

You can fix these things like this. I've included a /error500 sample route handler to show an example of how your route handlers trigger errors that are caught by your centralized error handler.

import express from 'express';
import 'dotenv/config';

const port = process.env.PORT;
const app = express();

// app.use(posts);
// app.use(users);

class RouteError extends Error {
    constructor(status, msg = "") {
        super(msg);
        this.status = status;
    }
}

if (process.env.NODE_ENV !== 'test') {
    app.listen(port, () => console.log(`Server listening on port ${port}`));
}

app.get('/api', (req, res, next) => {
    res.send('test')
})

// example that generates a 500 error
app.get('/error500', (req, res, next) => {
    next(new RouteError(500, "Custom 500 error message"));
});

app.use(app.router)

app.use(function(err, req, res, next) {
    switch (err.status) {
        case 500:
            res.status(500).json({
                "success": false,
                "code": 4001,
                "error": err.message || "Server Error"
            });
            break;
        case 404:
            res.status(404).json({
                "success": false,
                "code": 4001,
                "error": err.message || "Resource not found"
            });
            break;
        case 401:
            res.status(401).json({
                "success": false,
                "code": 2001,
                "error": err.message || "Unauthorized"
            });
            break;
        case 403:
            res.status(403).json({
                "success": false,
                "code": 2002,
                "error": err.message || "Forbidden"
            });
            break;

        default:
            res.status(404).json({
                "success": false,
                "code": 4001,
                "error": err.message || "Resource not found"
            });
            break;
    }
});

// 404 error handler
app.use((req, res, next) => {
    next(new RouteError(404));
});

export default app;

This adds a few embellishments. There's a custom Error class called RouteError that allows you to pass the desired status to the error object and an optional custom message that would override the default error message for that status. So, in some cases, you might want to give the client a bit more specific message than just the default message for a given status. This is optional. If not passed, the default message will be used.

  • Related