I have a schema defined like this:
const schema = joi.object().keys({
_id: Joi.string().guid().default(generateUUID, 'Random uuid v4.').required(),
string: Joi.string(),
// ... other keys here ...
}).options({
abortEarly: false,
convert: true,
allowUnknown: true,
stripUnknown: true,
noDefaults: false,
});
If I run schema.validate({}) without passing _id I get an output value with the correct default value applied to _id but also an error != null where it complains about _id being required
{
"error": {
"isJoi": true,
"name": "ValidationError",
"details": [
{
"message": "\"_id\" is required",
"path": "_id",
"type": "any.required",
"context": {
"key": "_id"
}
}
],
"_object": {
"string": "string value",
}
},
"value": {
"string": "string value",
"_id": "091a7172-1cc5-4b00-ac6c-d1460d74c604"
}
}
More details, this seems to happen only when using an extended schema:
let baseSchema = Joi.object().options({
abortEarly: false,
convert: true,
allowUnknown: true,
stripUnknown: true,
noDefaults: false,
});
let baseModel = baseSchema.keys({
_id: Joi.string().guid().default(generateUUID, 'Random uuid v4.').required(),
});
let model = baseModel.keys({
string: Joi.string(),
});
when validation model
Actually it happens also when not using an extended schema but in that case _id's default function is not applied at all
This is indeed the normal behavior with abortEarly false. You don't provide an id so required causes an error, then it goes on with the other rules, so default generate your uuid. You shouldn't mix required and default, it's contradictory.
@Marsup I get the point about abortEarly but why:
You shouldn't mix required and default, it's contradictory.
If I don't supply a value it should get the default value, required is to make sure that I can't pass a value like null. After default is applied the schema has a value and so the required rule shouldn't fail
null is denied by default. required is evaluated before default.
Thanks for clarification!
As a user of Joi I'd expect required() and default() to play nice together. But at least now I see how to override the behaviour to what I want. I'll use default() with optional() instead of required(), despite counter-intuitive (for me)
optional is the default, just don't put anything.
@Marsup you're right. But in my project required is default, hence the confusion.
This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions.
Most helpful comment
@Marsup I get the point about
abortEarlybut why:If I don't supply a value it should get the default value, required is to make sure that I can't pass a value like
null. After default is applied the schema has a value and so therequiredrule shouldn't fail