Skip to main content

Custom Validation Rules

To register a custom validation rule you must use the register method.

    const { register } = require('simple-body-validator');
    import { register } from 'simple-body-validator';

The register method takes three parameters:

  1. rule: The name of the rule.
  2. validate: A function that takes the attribute value and returns true if the validation is successful, or false otherwise.
  3. replaceMessage: Optional parameter to replace placeholders in the error message

Register method signature
register(
rule: string,
validate: (value: any, parameters?: string[], attribute?: string) => boolean,
replaceMessage?: (
message: string, paramters: string[], data?: object
) => string
): boolean;

Here is an example of a simple custom validation rule:

register('telephone', function (value) {
return /^\d{3}-\d{3}-\d{4}$/.test(value);
});

You can use the telephone rule in your validation rules:

import { make } from 'simple-body-validator';

const validator = make()
.setData({ cell: '+961 123 456 7890' })
.setRules({ cell: 'required|telephone'});

caution

You cannot register a rule that already exists. For example, you cannot register a rule named required since it already exists in the validation rules.

You can also specify the error message that should be returned in case the custom rule fails, by adding a new key value to the translation object.

import { setTranslationObject } from 'simple-body-validator';

setTranslationObject({
en: {
telephone: 'The :attribute phone number is not in the format XXX-XXX-XXXX.',
}
});

If you are not familiar on how to add error messages you can read about it here.

tip

The :attribute placeholder will be replaced by the actual name of the field under validation.

Accessing Additional Data In Your Custom Rule​

If your registered validation rule needs to access all the other data undergoing validation. You can use the this.data attribute.

    register('custom_rule', function (value) {
console.log(this.data);
});

Replace Placeholders in the Error Message​

In case you have a more complex use case, and you want to replace placeholders in the error message you can pass a method as a third parameter to the register method.

Let's say we want to register a new rule called complex_telephone. We will first start by adding the error message for that rule.

import { setTranslationObject } from 'simple-body-validator';

setTranslationObject({
en: {
complex_telephone: 'The :attribute phone number is not in the format +:code XXX-XXX-XXXX.',
}
});

In the case of the complex_telephone rule we would like to replace the :code placeholder dynamically.

register('complex_telephone', function (value, parameters) {
const [ code ] = parameters;
const pattern = new RegExp('^\\+' + code + ' \\d{3}-\\d{3}-\\d{4}$');
return pattern.test(value);
}, function(message, paramters) {
const [ code ] = paramters;
// replace the code in the message with the code sent in the parameters
return message.replace(':code', code);
});

Implicit Custom Rules​

By default, custom validation rules are not run if the attribute is not present or contains an empty string. To register a custom rule that runs even when the attribute is empty, you can use the registerImplicit() method.

The registerImplicit() method takes the same parameters as the register() method.

const { registerImplicit } = require('simple-body-validator');
import { registerImplicit } from 'simple-body-validator';

Here is an example of an implicit custom validation rule:

registerImplicit('required_if_type', function(value, parameters) {
const [ target, type ] = parameters;

if (typeof this.data[target] === type) {
// This a built in method that is actually used for the required rule
return this.validateRequired(value);
}

return true;
});

You can then use the required_if_type rule in your validation rules:

const validator = make()
.setData({ first: 'test' })
.setRule({ last: 'required_if_type:first,string' });

Custom Validation Rule Classes​

You can also create custom validation rule classes. A custom validation rule class must extend the Rule class, which has two methods

  • passes(): This method takes the attribute value and returns true if the validation is successful, or false otherwise.
  • getMessage(): This method returns the error message that should be used when validation fails.
const { Rule } = require('simple-body-validator');
import { Rule } from 'simple-body-validator';

Here is an example of a custom validation rule class:

class UpperCase extends Rule {
passes(value) {
if (typeof value != 'string') {
return false;
}

return value.toUpperCase() === value;
}

getMessage() {
return 'The :attribute must be uppercase.';
}
};

You can then use the custom validation rule class:

const validator = make(data, {
name: [ 'required', 'string', new UpperCase ],
});

If you wish to have translation for the UpperCase rule your can add a key value to the translation object and use the trans method in the getMessage method.

import { setTranslationObject } from 'simple-body-validator';

setTranslationObject({
en: {
uppercase: 'The :attribute must be uppercase.',
}
});

The getMessage implementation becomes as follows.

getMessage() {
return this.trans('uppercase');
}

Create a Custom Implicit Rule Using a Class​

If you want the validation to run even when the field is not available or empty you can use ImplicitRule object.

const { ImplicitRule } = require('simple-body-validator');
import { ImplicitRule } from 'simple-body-validator';

Below we will showcase a simple example on how to register an implicit rule.

const { ImplicitRule } = require('simple-body-validator');

class UpperCase extends ImplicitRule {
passes(value) {
// return either true or false
}

getMessage() {
// return error message
}
};

Accessing Additional Data In Your Class​

If your custom validation rule class needs to access all the other data undergoing validation. You can use the this.data method in the passes attribute.

passes(value) {
console.log(this.data);
}

The Trans Method​

As showcased in the previous example the trans method can be used to get messages from the translation files. The :attribute placeholder will be automatically replaced by the field name.

this.trans('uppercase');

If you have a more complex scenario where you need to replace more placeholders you can pass an object as second parameter to the trans method.

this.trans('required_if_type', [
target: this.target,
type: this.type,
]);

Using Closures​

You can also use closures to create custom validation rules. A closure is a function that has access to the variables in the scope in which it was created.

Here is an example of a closure-based custom validation rule:

const validator = make(data, {
title: [
'required',
'max:255',
function (value, fail, attribute) {
if (value === 'foo' {
// The trans method can also be passed to the fail method
fail(`The ${attribute} is invalid`);
});
},
],
});