OXp1845
OXp1845

Reputation: 493

Throw multiple exceptions in JavaScript

I'm wondering if there is a way to throw multiple errors and catch all of them in JavaScript.

I'm looking for specific fields, and when I find a missing one I would like to throw an error.

The problem is that if I throw a single error, like:

throw "you are missing field: " xxxxxx

I'm not telling the user all of the other fields which he/she is missing.

I would also not like to combine everything into a single string, since the error message might be too long.

Any ideas?

Thanks.

Upvotes: 11

Views: 23857

Answers (4)

Channaveer Hakari
Channaveer Hakari

Reputation: 2927

I basically throw errors from my service classes or service methods with exact exception names so that later we can handle them according to the exception name like the following

try{
    const user = User.findOne({ _id: request.body.user_id });
    
    if (!user) {
        throw new Error ("USER_NOT_FOUND_EXCEPTION")
    }
    
    const articles = Article.find({ user_id: user._id });
    
    if (!articles) {
        throw new Error ("USER_ARTICLES_NOT_FOUND_EXCEPTION")
    }

    //Rest of the code goes below
    return response.status(200).json({
        status: "success"
    });
}catch(error) {
    /** Handle specific exceptions */
    if (error.message == "USER_NOT_FOUND_EXCEPTION") {
        return response.status(400).json({
            status: "error",
            message: "User details not found."
        });
    }

    if (error.message == "USER_ARTICLES_NOT_FOUND_EXCEPTION") {
        return response.status(400).json({
            status: "error",
            message: "User articles not found."
        });
    }

    /** Handle generic exceptions */
    return response.status(400).json({
        status: "error",
        message: error.message
    });
}

Upvotes: 0

aug
aug

Reputation: 11714

Hey so currently dealing with an issue related to this. Just wanted to add a couple thoughts.

throw allows you to throw any expression and it will generate an exception which will kick into the catch clause if it exists with the value populated as the parameter (typically an Error). This is user-defined though so you can essentially throw whatever you want.

So if you really wanted to throw an array of exceptions, you totally can. i.e. something like this

try {
  var errors = [];
  for (let i=0; i<10; i++) {
    errors.push(new Error('Here is a special exception'));
  }

  if (errors.length > 0) {
    throw errors; 
  }

} catch(e) {
    for (let i=0; i<e.length; i++) {
      console.log(e[i]);
    }
}

I think some things to be aware of

  • can your function throw different types? If you can throw arrays, numbers, exceptions, any other expressions, you'll need to handle all those cases. Generally people will move this into their own error handler, so you'll need to handle collections in this case
  • be careful of nested try/catch statements. You would normally need to be aware of this but throwing it out there (haha!) anyways for sanity purposes.
  • When handling async code where errors can get populated into the array at different times, make sure to utilize await and Promise.all before going through (unless you don't mind missing out on exceptions).

In terms of how good/bad practice it is, I honestly couldn't find much about it. I would say tread lightly and understand if your use case really needs this. Sometimes it's helpful but you may not need to process the entire array of exceptions.

Hope this helps.

Upvotes: 4

You create your own type of Error that holds the list of missing fields:

class MissingFieldsError extends Error {
  constructor(fields, ...params) {
    super(...params);
    this.fields_ = fields;
  }

  getMissingFields() {
    return this.fields_;
  }
}

To use it, you can gather all of the missing fields first and then throw an instance of MissingFieldsError. Assuming you have some sort of array of Field instances, the code should look like this:

const missingFields = fields
    .filter((field) => field.isMissing())
    .map((field) => field.getName());

if (missingFields.length > 0) {
  throw new MissingFieldsError(
      missingFields, 'Some required fields are missing.');
}

If you prefer, you can even have separate Errors thrown, collect them and then throw the MissingFieldsError:

const missingFields = [];

fields.forEach((field) => {
  try {
    const value = field.getValue();
    // Process the field's value.

    // Could be just field.validate();
  } catch (e) {
    missingFields.push(field.getName());
  }
});

if (missingFields.length > 0) {
  throw new MissingFieldsError(
      missingFields, 'Some required fields are missing.');
}

Upvotes: 6

doldt
doldt

Reputation: 4506

You can throw any kind of object, you're not limited to strings, so you might as well collect your error messages into an object, and throw that in the end, if any errors were present.

Upvotes: 5

Related Questions