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:
rule
: The name of the rule.validate
: A function that takes the attributevalue
and returnstrue
if the validation is successful, orfalse
otherwise.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 returnstrue
if the validation is successful, orfalse
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`);
});
},
],
});