0

Our model layer in our app will generate an array of errors that may or may not contain objects. As an example, say someone wanted to POST a thing to our api and the user submitted an invalid payload, an example validation error array may look like so:

["foo is required", 
 "bar must be a string", 
 { orders: ["id is required", "name must be a string"]}]

Notice how orders is an object - that's because orders is a an object with its own properties that should be posted in the payload and we wanted to namespace any validation errors under that object to make it more clear to the end user.

All is fine and dandy until our framework calls new Error(validationErrors) before returning a 400 Bad Request.

This is what the error message ends up looking like:

{"statusCode": 400,
 "error":"Bad Request",
 "message":"foo is required,bar must be a string, [object Object]"}

You can see that the nested orders validation object has been lost.

As a short-term fix, I've JSON.stringified the validationErrors array, but that ends up causing the error to look like:

{"statusCode":400,
 "error":"Bad Request",
 "message":"[\"the value of active is not allowed to be undefined\",\"the value of name is not allowed to be undefined\",\"the value of team is not allowed to be undefined\",\"the value of startDate is not allowed to be undefined\",\"the value of endDate is not allowed to be undefined\",{\"location\":[\"the value of name is not allowed to be undefined\",\"the value of latitude is not allowed to be undefined\",\"the value of longitude is not allowed to be undefined\"]}]"}

Is there a better solution to this problem?

1 Answer 1

2

Given the input:

var errors = [
 "foo is required", 
 "bar must be a string", 
 { orders: ["id is required", "name must be a string"]}
];

You can transform it into this output:

[
 "foo is required",
 "bar must be a string", 
 "orders: id is required",
 "orders: name must be a string"
]

Since you didn't provide your expected output, I just made that up.


The code:

errs.reduce(function(output, current){
  if (typeof current == 'object') {
    var key = Object.keys(current)[0];
    output = output.concat(current[key].map(function(err) {
      return key + ': ' + err;
    }));
  }
  else {
    output.push(current);
  }
  return output;
}, []);

Explanation:

arr.reduce takes two parameters: a function that is called for every element in an array, and the initial value which collects the outputs of the first function.

arr.map takes one parameter: a function which transforms each element of the context array.

So we start with errs.reduce, with an initial value of []. We will look at every error in the input array. If it is a string, we push it onto the output array. If it is an object, then we transform {orders: ['error one', 'error two']} into ['orders: error one', 'orders: error two'] by keeping track of the key (Object.keys()[0]), and using map to transform.

Sign up to request clarification or add additional context in comments.

1 Comment

Yea, I like that approach too. Since I wrote the validator, I can just fix it there.

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.