4

I am working on an API and I am trying to manage errors in a clean way. So I tried to define a module gathering all Error subclasses that I might want to throw in my API.
Those classes correspond to HTTP error codes that I'd like to return to the requester. I chose to put them in a module all by themselves because I will use them in several other modules as well.

I would like to use my Error subclasses like this:

require('../apiErrors');

function apiRequest(req, res) {
   doRequest(req, function (err, data) {
        if (err) {
            throw new BadRequestError('Request is not good');
        }
        res.send(200, data);
   }) 
}

And my module is defined like this: apiErrors.js

module.exports = () => {
    class UnauthorizedError extends Error {
        constructor(message) {
             super(message);
             this.name = 'UnauthorizedError';
             this.code = 403;
        }
    }

    class NotFoundError extends Error {
        constructor(message) {
            super(message);
            this.name = 'NotFoundError';
            this.code = 404;
        }
    }

    class BadRequestError extends Error {
        constructor(message) {
            super(message);
            this.name = 'BadRequestError';
            this.code = 400;
        }
    }
};

The outcome of this is a ReferenceError: BadRequestError is not defined. At this point I wonder if my way of doing it is indeed clean and what I am missing when exporting my apiErrors module.

3
  • Why did you put your class declarations inside an arrow function? Commented Nov 5, 2018 at 10:24
  • I was hoping to define my classes by having a self launching function but it didn't work. I tried some other solutions but I didn't think about getting rid of it. I'm currently trying the solution provided by T.J. Crowder below. I hope it works Commented Nov 5, 2018 at 11:08
  • You don't need any "self-launching functions" when working with a module system such as the one in node.js. Commented Nov 5, 2018 at 17:45

1 Answer 1

6

You have two problems:

  1. You're not exporting the classes. You're exporting a function that would create the classes if you called it, but then would throw them away because it doesn't do anything with them.

  2. You're not doing anything with the result of require('../apiErrors');

To fix #1, either:

class UnauthorizedError extends Error {
    constructor(message) {
         super(message);
         this.name = 'UnauthorizedError';
         this.code = 403;
    }
}

class NotFoundError extends Error {
    constructor(message) {
        super(message);
        this.name = 'NotFoundError';
        this.code = 404;
    }
}

class BadRequestError extends Error {
    constructor(message) {
        super(message);
        this.name = 'BadRequestError';
        this.code = 400;
    }
};
module.exports = {
    UnauthorizedError,
    NotFoundError,
    BadRequestError
};

or

module.exports.UnauthorizedError = class UnauthorizedError extends Error {
    constructor(message) {
         super(message);
         this.name = 'UnauthorizedError';
         this.code = 403;
    }
};

module.exports.NotFoundError = class NotFoundError extends Error {
    constructor(message) {
        super(message);
        this.name = 'NotFoundError';
        this.code = 404;
    }
};

module.exports.BadRequestError = class BadRequestError extends Error {
    constructor(message) {
        super(message);
        this.name = 'BadRequestError';
        this.code = 400;
    }
}

To fix #2, in your example where you're just using BadRequestError:

const { BadRequestError } = require('../apiErrors');

or

const BadRequestError = require('../apiErrors').BadRequestError;

or

const ErrorClasses = require('../apiErrors');
// ...then to use one of them...
throw new ErrorClasses.BadRequestError('Request is not good');
Sign up to request clarification or add additional context in comments.

4 Comments

I used the fix #1 associated with the deconstructed object type of require (the first one). Thank you very much for your solution, it works like a charm
@SeddikiAnass - No worries! :-) (BTW, it's "destructured" rather than "deconstructed.")
Thanks for the reminder, it's a word I discovered recently so I'm still mixing it up.
@SeddikiAnass - I made exactly the same mistake when I first learned it. :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.