On v6.0.8, for object arrays, the stripUnknown option does not result in errors when the validation for one of the object keys fails, like the following example:
var Joi = require('joi');
var schema = Joi.array().items(Joi.object().keys({
one: Joi.string(),
two: Joi.number()
})).options({ stripUnknown: true });
schema.validate([{ one: 'one', two: 'two' }], function (err, value) {
console.log('err:', err);
console.log('value:', value);
});
Is this the expected behaviour or is it a bug? I don't recall this happening on previous versions. If it's a bug, I'll gladly send a pull request.
Thanks!
This is the expected behavior. The release notes explained that, it seems the documentation doesn't. It seems like the logical thing to do but I'd accept a PR to clarify that.
I think it is a little bit misleading, because for this particular case, we are not talking about unknown object keys but invalid values for known keys.
Anyway, my issue is that I'm setting a global value for the option on hapi, but I guess I can just override it for the specific cases where I want strict validation.
They are not invalid if you use that option, stripUnkown has the same behavior as on objects.
Yes, I know, I'm just saying that maybe stripUnknown is not the best name for what it does (in this particular case, at least).
Although this issue is closed, I think that there's a huge difference between what stripUnknown _implies_ it does (removing unknown keys from an object) and what it _actually_ does in the context of arrays of objects (removing items from an array that aren't valid per the defined schema). This is very confusing behavior.
If I want to validate an array of objects as part of a larger schema, stripping out unknown keys on the parent object:
var schema = Joi.object().keys({
dish: Joi.string(),
ingredients: Joi.array().items(
Joi.object().keys({
name: Joi.string(),
amount: Joi.number(),
})
)
})
var data = {
dish: 'Mac and Cheese',
ingredients: [{
name: 'Macaroni',
amount: 'one'
}, {
name: 'Cheese',
amount: 'two'
}],
unnecessaryInfo: 'Blah Blah...'
}
var result = Joi.validate(data, schema, { stripUnknown: true })
What I think is reasonable to expect is for the validation to fail, since the objects passed into the ingredients array don't match the defined schema.
// What I expect to see
// result.error -> [ValidationError: child "ingredients" fails because ["ingredients" at position 0 fails because [child "amount" fails because ["amount" must be a number]]]
Instead, the objects that don't pass validation are stripped out of the array.
result.value = {
dish: 'Mac and Cheese',
ingredients: []
}
I think this behavior is very misleading - These fields aren't unknown, they're invalid. I also think it's quite misleading for the behavior of stripping unknown keys from an object to be conflated with stripping mismatching items in an array. There's a very large difference between these two behaviors, and I think it would be much more reasonable to define a property on the array schema definition that determines what behavior Joi ought to take when encountering this kind of situation.
In any case, the workaround is verbose, unclear, and prone to error. One needs to define stripUnkown to false on the array, and true on the member objects:
var schema = Joi.object().keys({
dish: Joi.string(),
ingredients: Joi.array().items(
Joi.object().keys({
name: Joi.string(),
amount: Joi.number(),
}).options({stripUnknown: true})
).options({stripUnknown: false})
})
var result = Joi.validate(data, schema, { stripUnknown: true })
Agree to disagree. Stripping unknown keys from an object isn't that different from stripping unknown values from an array. Though a separate flag wouldn't hurt I guess. Can you create a new issue to track it ?
The confusing part is the adjective, not the verb. In one case you are in fact stripping unknown (keys). In the array-of-schema scenario, you're really stripping _invalid_ (values). No array index is unknown or outside the schema expecting that array, unless by virtue of bounds on the size of a non-sparse array.
To me it would make a lot of sense to handle these behaviors separately with unique methods, stripUnknown and stripInvalid, with stripInvalid working on values in arrays and objects, but stripUnknown only working on keys of objects.
It's already a solved problem.
Most helpful comment
Although this issue is closed, I think that there's a huge difference between what
stripUnknown_implies_ it does (removing unknown keys from an object) and what it _actually_ does in the context of arrays of objects (removing items from an array that aren't valid per the defined schema). This is very confusing behavior.If I want to validate an array of objects as part of a larger schema, stripping out unknown keys on the parent object:
What I think is reasonable to expect is for the validation to fail, since the objects passed into the ingredients array don't match the defined schema.
Instead, the objects that don't pass validation are stripped out of the array.
I think this behavior is very misleading - These fields aren't unknown, they're invalid. I also think it's quite misleading for the behavior of stripping unknown keys from an object to be conflated with stripping mismatching items in an array. There's a very large difference between these two behaviors, and I think it would be much more reasonable to define a property on the array schema definition that determines what behavior Joi ought to take when encountering this kind of situation.
In any case, the workaround is verbose, unclear, and prone to error. One needs to define
stripUnkowntofalseon the array, andtrueon the member objects: