Shifut Hossain
Shifut Hossain

Reputation: 1699

How to add custom validator function in Joi?

I have Joi schema and want to add a custom validator for validating data which isn't possible with default Joi validators.

Currently, I'm using the version 16.1.7 of Joi

const method = (value, helpers) => {
  // for example if the username value is (something) then it will throw an 
  // error with the following message but it throws an error inside (value) 
  // object without error message. It should throw error inside the (error) 
  // object with a proper error message
        
  if (value === "something") {
    return new Error("something is not allowed as username");
  }

  return value; // Return the value unchanged
};
        
const createProfileSchema = Joi.object().keys({
  username: Joi.string()
    .required()
    .trim()
    .empty()
    .min(5)
    .max(20)
    .lowercase()
    .custom(method, "custom validation")
});
        
const { error, value } = createProfileSchema.validate({
  username: "something" 
});
        
console.log(value); // returns {username: Error}
console.log(error); // returns undefined

But I couldn't implement it the right way. I read Joi documents but it seems a little bit confusing to me. Can anyone help me to figure it out?

Upvotes: 33

Views: 59600

Answers (4)

nosang
nosang

Reputation: 29

recently faced the same isuue, hope this helps.

//joi object schema     
password: Joi.custom(validatePassword, "validate password").required(),


// custom validator with custom message
// custom.validation.ts

import { CustomHelpers } from "joi";

const validatePassword = (value: string, helpers: CustomHelpers) => {
  if (value.length < 6) {
    return helpers.message({
      custom: "Password must have at least 6 characters.",
    });
  }

  if (!value.match(/\d/) || !value.match(/[a-zA-Z]/)) {
    return helpers.message({
      custom: "Password must contain at least 1 letter and 1 number.",
    });
  }

  return value;
};

export { validatePassword };

Upvotes: 1

Muslem Omar
Muslem Omar

Reputation: 1121

const Joi = require('@hapi/joi');
    
Joi.object({
  password: Joi
    .string()
    .custom((value, helper) => {
      if (value.length < 8) {
        return helper.message("Password must be at least 8 characters long");
      }

      return true;
    })
}).validate({
    password: '1234'
});

Upvotes: 44

SuleymanSah
SuleymanSah

Reputation: 17858

Your custom method must be like this:

const method = (value, helpers) => {
  // for example if the username value is (something) then it will throw an 
  // error with the following message but it throws an error inside (value) 
  // object without error message. It should throw error inside the (error) 
  // object with a proper error message

  if (value === "something") {
    return helpers.error("any.invalid");
  }

  return value; // Return the value unchanged
};

Docs:

https://github.com/hapijs/joi/blob/master/API.md#anycustommethod-description

Output for value :

{ username: 'something' }

Output for error:

[Error [ValidationError]: "username" contains an invalid value] {
  _original: { username: 'something' },
  details: [
    {
      message: '"username" contains an invalid value',
      path: [Array],
      type: 'any.invalid',
      context: [Object]
    }
  ]
}

Upvotes: 37

Isaac
Isaac

Reputation: 37

This is how I validated my code, have a look at it and try to format yours

const busInput = (req) => {
  const schema = Joi.object().keys({
    routId: Joi.number().integer().required().min(1)
      .max(150),
    bus_plate: Joi.string().required().min(5),
    currentLocation: Joi.string().required().custom((value, helper) => {
      const coordinates = req.body.currentLocation.split(',');
      const lat = coordinates[0].trim();
      const long = coordinates[1].trim();
      const valRegex = /-?\d/;
      if (!valRegex.test(lat)) {
        return helper.message('Laltitude must be numbers');
      }
      if (!valRegex.test(long)) {
        return helper.message('Longitude must be numbers');
      }
    }),
    bus_status: Joi.string().required().valid('active', 'inactive'),
  });
  return schema.validate(req.body);
};

Upvotes: 2

Related Questions