NAME
Validate::Simple - (Relatively) Simple way to validate input parameters
SYNOPSIS
use Validate::Simple;
my $specs = {
username => {
type => 'string',
required => 1,
},
first_name => {
type => 'string',
required => 1,
},
last_name => {
type => 'string',
},
age => {
type => 'integer',
gt => 18,
},
gender => {
type => 'enum',
values => [
'male',
'female',
'id_rather_not_to_say',
],
},
tags => {
type => 'array',
of => {
type => 'string',
},
},
hobbies => {
type => 'array',
of => {
type =>'enum',
values => [ qw/hiking travelling surfing laziness/ ],
},
},
score => {
type => 'hash',
of => {
type => 'non_negative_int',
},
},
monthly_score => {
type => 'hash',
of => {
type => 'hash',
of => {
type => 'array',
of => {
type => 'non_negative_int',
},
callback => sub {
@{ $_[0] } < 12;
},
},
},
},
address => {
type => 'spec',
of => {
country => {
type => 'enum',
values => [ qw/ af ax al ... zw / ],
},
zip_code => {
type => 'string',
},
street => {
type => 'string',
},
number => {
type => 'spec',
of => {
house_nr => {
type => 'positive_int',
},
house_ext => {
type => 'string',
},
apt => {
type => 'positive_int',
},
},
},
},
},
};
my $vs1 = Validate::Simple->new( $specs );
my $is_valid1 = $vs1->validate( $params );
print join "\n", $vs1->errors()
if !$is_valid1;
# Or
my $vs2 = Validate::Simple->new();
my $is_valid2 = $vs2->validate( $params, $specs );
print join "\n", $vs2->errors()
if !$is_valid2;
DESCRIPTION
The module validates parameters against specifications.
LOGIC
The general use case is the like this.
You have a from handler or a handler of an API endpoint. It receives a hashref as a parameter. You want to make sure that the input hashref has all the required keys, you do not have unknown keys, and all the values satisfy certain criterias: type, size and other constraints...
Validate::Simple
allows you to specify criterias for each input parameter in a (relatively) simple form and validate user input against your specification as many times as you need. A specification is just a hashref. The keys repeat parameters names, the values define criterias.
For example:
my $specs = {
username => {
type => 'string',
required => 1,
min_length => 1,
max_length => 255,
},
password => {
type => 'string',
required => 1,
min_length => 12,
},
subscriptions => {
type => 'array',
empty => 0,
of => {
type => 'positive_int',
},
}
};
This specification can be used to validate a sign up form. Validation passes only if user enters a non-empty username no longer than 255 character, a password no shorter than 12 characters and chooses 0 or more subscriptions (which are supposed to be provided as a list of IDs, i.e. positive integers. The list of subscriptions may absent (no required
key in the rule), but if it exists, it cannot be empty (because of the value of the empty
key is set to 0
).
If input data contains a key 'remember_me'
, validation fails, because specification does not define rules for this key.
EXPORT
This module does not export anything. It is supposed to be used in OOP approach only.
SPECIFICATIONS (SPECS)
Specifications are the rules that describe which parameters are expected, their types and constraints (like lengths of strings or signs of numbers). Specification is just a hashref, the keys are parameters names, and the values describe criterias.
Every description must have a type
key, and may have the keys required
, undef
and callback
.
Common specs keys
type
The value of type
defines an expected type of a parameter. If omitted, type 'any'
is used. You can learn more about supported types in the "Types" section.
required
When it is set to a true value, the parameter is required, and, if it is not in the input data, the form is considered invalid. When it is set to a false value or does not exists, the parameter is optional.
undef
By default none parameters can be undefined. If you expect some values to be undefined, you need to explicitly set this key to true.
For example, if you allow the value of the param to be literally anything, you can do the following:
my $specs = {
whatever => {
type => 'any',
undef => 1,
}
};
callback
If you have some special constraints to a value that does not fit to any of supported types, you can specify your own validation function and pass it to callback
key as a coderef. The function should receive the value as a first parameter and returns true or false.
For example, if you need to check whether a value is an even positive integer, you can do the following:
my $specs = {
even_positive => {
type => "positive_int",
callback => sub { !( $_[0] % 2 ) },
},
};
In case of the "enum" type, the second parameter is the hashref with the keys of allowed enum values.
The callback function is called after checking the type and constraints.
Types
any
The value can be of any type (including array or hash), except undef
.
Number types
All number types support the following keys:
- gt
-
Greater than.
- ge
-
Greater than or equal to.
- lt
-
Less than.
- le
-
Less than or equal to.
For example, the following spec checks whether it's a valid month number:
my $specs = {
month => {
type => 'positive_int',
le => 12,
},
};
number
The value is a valid number. On the backstage it simply performs looks_like_number from Scalar::Util.
positive
Same as "number", and checks whether it's greater than 0.
non_negative
Same as "number", and checks whether it's greater than or equal to 0.
negative
Same as "number", and checks whether it's greater than 0.
non_positive
Same as "number", and checks whether it's less than or equal to 0.
integer
The value is an integer. It performs is_int from Data::Types.
positive_int
The value is a positive integer. It performs is_count from Data::Types.
non_negative_int
The value is a non-negative integer. It performs is_whole from Data::Types.
negative_int
The value is a negative integer.
non_positive_int
The value is a non-positive integer.
string
The value is a string. It performs is_string from Data::Types.
NOTE: Any number is a valid string, so both $params1 = { string_param => 5 };
and $params1 = { string_param => "5" };
will pass.
You can add the following constraints to a string:
- max_length
-
Positive integer number that defines the maximum string length allowed.
- min_length
-
Positive integer number that defines the minimum string length allowed.
- re
-
Regilar expression. The value will be checked aginst this regexp.
For example:
my $specs = { str_re => { type => 'string', re => qr/Valid/, } };
List types
The list types must have the key of
, which contains a spec of all list values. For example:
my $specs = {
ids => {
type => 'array',
of => {
type => 'positive_int',
},
},
placeholders => {
type => 'hash',
of => {
type => 'string',
},
},
};
As long as the of
key expects another specification, you can easily validate complex structures, like array of arrays of strings, hash of arrays of hashes of enums, arrays of hashes of arrays of arrays of any, and so on.
By default lists cannot be empty. If you expect an empty list, you should add a key empty
and set it to a true value.
array
The value is an arrayref.
hash
The value is a hashref.
enum
The value is one of the predefined list.
Enum type always contains a string. The list of predefined strings is provided in the values
key, which is required for enums:
my $specs = {
data_types => {
type => 'enum',
values => [
qw/
any
number
positive
non_negative
negative
non_positive
integer
positive_int
non_negative_int
negative_int
non_positive_int
string
array
hash
enum
code
/
],
}
};
code
The value is a coderef. Validate::Simple only checks the type, it does not run the code and does not check its result.
spec
The value is another structure, of hashref with predefined keys and values of different types. The type spec
requires the key of
, which, in turn, expects another valid specification. Obviously, a specification may contain as many nested specifications as necessary.
my $resume_spec = {
name => {
type => 'string'
},
objective => {
type => 'string'
},
experience => {
type => 'array',
of => {
type => 'spec',
of => {
company => {
type => 'string',
},
position => {
type => 'string',
},
description => {
type => 'string',
},
start => {
type => 'spec',
of => {
year => {
type => 'integer',
gt => 1960,
le => 1900 + (localtime)[5],
},
month => {
type => 'positive_int',
lt => 12,
},
},
required => 1,
},
end => {
type => 'spec',
of => {
year => {
type => 'integer',
gt => 1960,
le => 1900 + (localtime)[5],
},
month => {
type => 'positive_int',
lt => 12,
},
},
required => 0,
},
},
},
},
};
METHODS
new( \%spec[, $all_errors] )
Creates an object. The parameter is optional, though it's recomended to pass it, because in this case it checks specs syntax only once, not on each call of validate
method.
By default the module stops validation after finding the first invalid value. If the second parameter $all_errors
is true, the call of the validate
method will keep checking all \%params
and will stack all found errors. The list of errors is returned by the errors
method.
validate( \%params, [\%specs[, $all_errors]] )
Does validation of the \%params
against \%specs
. If \%specs
is not provided, it performs validation against the spec, given in the new
method. Returns 1 if \%params
are valid, undef
otherwise.
The parameter $all_errors
works the same way as in the new()
method.
errors
Returns the list of validation errors. The list is being emptied before each call of the validate
method.
BUGS
Not reported... Yet...
SEE ALSO
AUTHOR
Andrei Pratasavitski <andreip@cpan.org>
LICENSE
This is free software; you can redistribute it and/or modify it under the same terms as Perl itself.