Creating your first JOI extension

So this is going to be a super short primer for people who’re trying to write JOI extensions. I recently wrote an extension to validate mongodb object IDs and I’ll document the steps for the same here; Let’s get started

Joi uses something called as extension objects to “extend” its functionality.
These objects typically look something like this:

{
base: any_joi_base_function_you_want_to_use,
name: 'the_name_of_your_validation',
language: { // This is where you'd store error messages
'key_name': 'Error messages',
},
pre(value, state, options) {
you can parse the object value here or
even add a base check and throw error
},
rules: [{
name: 'name_of_sub_validation',
validate(params, value, state, options) {
if (some_condition_doesn't_match) {
return this.createError(
'path_to_err_in_language',
{ v: value },
state,
options
);
}
return value;
},
}, ...more_rules],
}

now, we can either pass this object as an argument to the Joi.extend method or create a function that returns an object like that 👆
Joi says you can also pass an array of a combination of the two; I haven’t tried it.

Coming to the object-id extension, we know that object-ids are essentially strings. So we can use the Joi.string methods as the base. For the name, let’s call it dbId. Why? We could club multiple rules here. Say you also have a postgres table that uses UUID as ids. 🤷‍♂
For now, though, let’s stick to creating just one rule; for mongoDb, mongoid.

How do we validate whether a string is a valid mongo id?

The function we can use here is the mongoose.Types.ObjectId.isValid. As obvious, it returns a true/false depending on the value passed.

Plugging all the pieces together

const extention = joi => ({
base: joi.string(),
name: 'dbId',
language: {
mongoid: 'needs to be a valid object id',
},
rules: [{
name: 'mongoid',
validate(params, value, state, options) {
if (!Mongoose.Types.ObjectId.isValid(value)) {
return this.createError(
'dbId.mongoid',
{ v: value },
state,
options
);
}
return value;
},
}],
});

Now all you’ve got to do is extend the original Joi object with the factory method and you’re good to go 👍

const Joi = require('@hapi/joi');const CustomJoi = Joi.extend(extention);// You can now use CustomJoi.dbId().mongoid() as a validation in your schemas!

Yep; that’s all there is to it;
You can find the code and npm link for this package here:

Cheers! ☕️

@szanwar22 on twitter :D

Love podcasts or audiobooks? Learn on the go with our new app.