=head1 NAME Web::DataService::Configuration::Ruleset - how to configure parameter rulesets =head1 SYNOPSIS This page describes the role that parameter rulesets play in the Web::DataService framework, and how to configure them. It includes a list of the attributes that you can use to define them. =head1 RULESET DEFINITIONS Each data service may define one or more groups of rules for validating request parameters, called "rulesets". These are defined by calling the L method of a data service object. The first argument to C must be a string that provides the name of the ruleset. This must be unique among all of the rulesets defined for this data service. The remaining elements must be either hashrefs or strings: the hashrefs define the individual rules, and the strings provide documentation. For example: $ds->define_ruleset( 'filters' => { param => 'lat', valid => DECI_VALUE('-90.0','90.0') }, "Return all datasets associated with the given latitude.", { param => 'lng', valid => DECI_VALUE('-180.0','180.0') }, "Return all datasets associated with the given longitude.", { together => ['lat', 'lng'], errmsg => "you must specify 'lng' and 'lat' together" }, "If either 'lat' or 'lng' is given, the other must be as well.", { param => 'id', valid => POS_VALUE }, "Return the dataset with the given identifier", { param => 'name', valid => STR_VALUE }, "Return all datasets with the given name"); These rulesets are selected using the node attribute C. When a data service request is handled, its parameters are automatically validated against the ruleset (if any) specified by corresponding data service node. If the validation fails, then an HTTP 400 error ("bad request") is returned to the client along with one or more error messages indicating how the parameter values should be adjusted. If the validation succeeds but warnings are generated, those warnings are included as part of the response message. If the validation succeeds, the cleaned parameter values are made available through methods of the request object such as L and L). Ruleset validation is handled by the module L. The Web::DataService method alters the ruleset definitions as specified below, and then hands off the resulting rulesets to the latter module. See that module's documentation for more information about how this process works. =head1 RULESET ATTRIBUTES Each rule in a ruleset has a type. The rule type is indicated by the presence of a hash key corresponding to the type; each rule must have exactly one such key. The rule type keys are as follows: =head2 parameter rules The following three types of rules define the recognized parameter names. =head3 param { param => , valid => ... } If the specified parameter is present, then its value must pass one of the specified validators. If it passes any of them, the rest are ignored. If it does not pass any of them, then an appropriate error message will be generated. If no validators are specified, then the value will be accepted no matter what it is. =head3 optional { optional => , valid => ... } An C rule is identical to a C rule, except that the presence or absence of the parameter will have no effect on whether or not the containing ruleset is fulfilled. A ruleset in which all of the parameter rules are C will always be fulfilled. This kind of rule is useful in validating URL parameters, especially for GET requests. A special syntax is available which automatically generates validation rules for any special parameters that have been enabled for this data service. You can provide any of the following as the parameter name in a rule of type C: =over 4 =item C This generates a rule for the specified special parameter, with the attributes defaulting to appropriate values. You are free to override these by specifying any of the attributes explicitly. Standard documentation is provided by default, unless you specifically provide your own. For example, the following definition will change the set of acceptable values for the special parameter C. { param => 'SPECIAL(linebreak)', valid => ENUM_VALUE('cr', 'crlf', 'foo') } You will often use this form with the special parameter C, which is not included in the lists shown below because the set of values it can take may vary. Unless your data service is very simple, you will probably need to define multiple rulesets that specify this parameter, selecting the appropriate validation set for each one. For example, the following definition specifies that the valid values for the special parameter C will be the values defined for the set C. See the L for an example of how these are used. { param => 'SPECIAL(show)', valid => 'extra' } =item C This generates a list of rules, one for each enabled special parameter except C and possibly C, and except for any special parameters that have been already defined in this ruleset. The C parameter is never included, and C is only included if any vocabulary other than C has been defined for this data service. Each of these generated rules includes standard documentation strings. If you wish to override these for certain parameters, define them explicitly using the form discussed above. =item C This works similarly to C, but only includes those parameters that are relevant to single-record results. The parameters C, C, and C are skipped. =back =head3 mandatory { mandatory => , valid => ... } A C rule is identical to a C rule, except that the parameter is required to be present with a non-empty value. If it is not, then an error message will be generated. This kind of rule can be useful when validating HTML form parameters. =head2 parameter constraint rules The following rule types can be used to specify additional constraints on the presence or absence of parameter names. =head3 together { together => [ ... ] } If one of the listed parameters is present, then all of them must be. This can be used with parameters such as 'longitude' and 'latitude', where neither one makes sense without the other. =head3 at_most_one { at_most_one => [ ... ] } At most one of the listed parameters may be present. This can be used along with a series of C rules to require that exactly one of a particular set of parameters is provided. =head3 ignore { ignore => [ ... ] } The specified parameter or parameters will be ignored if present, and will not be included in the set of reported parameter values. This rule can be used to prevent requests from being rejected with "unrecognized parameter" errors in cases where spurious parameters may be present. If you are specifying only one parameter name, it does need not be in a listref. =head2 inclusion rules The following rule types can be used to include one ruleset inside of another. This allows you, for example, to define rulesets for validating different groups of parameters and then combine them into specific rulesets for use with different URL paths. It is okay for an included ruleset to itself include other rulesets. However, any given ruleset is checked only once per validation no matter how many times it is included. =head3 allow { allow => } A rule of this type is essentially an 'include' statement. If this rule is encountered during a validation, it causes the named ruleset to be checked immediately. It must pass, but does not have to be fulfilled. =head3 require { require => } This is a variant of C, with an additional constraint. The validation will fail unless the named ruleset not only passes but is also fulfilled by the parameters. You could use this, for example, with a query-type URL in order to require that the query not be empty but instead contain at least one significant criterion. The parameters that count as "significant" would be declared by C rules, the others by C rules. =head2 inclusion constraint rules The following rule types can be used to specify additional constraints on the inclusion of rulesets. =head3 require_one { require_one => [ ... ] } You can use a rule of this type to place an additional constraint on a list of rulesets already included with C rules. Exactly one of the named rulesets must be fulfilled, or else the request is rejected. You can use this, for example, to ensure that a request includes either a parameter from group A or one from group B, but not both. =head3 require_any { require_any => [ ... ] } This is a variant of C. At least one of the named rulesets must be fulfilled, or else the request will be rejected. =head3 allow_one { allow_one => [ ... ] } Another variant of C. The request will be rejected if more than one of the listed rulesets is fulfilled, but will pass if either none of them or just one of them is fulfilled. This can be used to allow optional parameters from either group A or group B, but not from both groups. =head2 Other attributes Any rule definition may also include one or more of the following keys: =head3 errmsg This key specifies the error message to be returned if the rule fails, overriding the default message. For example: $ds->define_ruleset( 'specifier' => { param => 'name', valid => STRING_VALUE }, { param => 'id', valid => POS_VALUE }); $ds->define_ruleset( 'my_operation' => { require => 'specifier', errmsg => "you must specify either of the parameters 'name' or 'id'" }); Error messages may include any of the following placeholders: C<{param}>, C<{value}>. When included with a parameter rule these are replaced by the parameter name and original parameter value(s), single-quoted. When used with other rules, {param} is replaced by the full list of relevant parameters or ruleset names, quoted and separated by commas. This feature allows you to define common messages once and use them with multiple rules. =head2 warn This key causes a warning to be generated rather than an error if the rule fails. Unlike errors, warnings do not cause a request to be rejected. Instead, they will automatically be returned as part of the data service response. If the value of this key is 1, then what would otherwise be the error message will be used as the warning message. Otherwise, the specified string will be used as the warning message. =head2 key The key 'key' specifies the name under which any inforamtion generated by the rule will be saved. For a parameter rule, the cleaned value will be saved under this name. For all rules, any generated warnings or errors will be stored under the specified name instead of the parameter name or rule number. This allows you to easily determine after a validation which warnings or errors were generated. The following keys can be used only with rules of type C, C or C: =head2 valid This key specifies the domain of acceptable values for a parameter. The value must be either a single string, a single code reference, or a list of code references. If you provide a string, it must be the name of a L previously defined for this data service. Otherwise, you can either select from the list of L or L. If the parameter named by this rule is present, it must pass at least one of the specified validators or else an error message will be generated. If multiple validators are given, then the error message returned will be the one generated by the last validator in the list. This can be overridden by using the L key. =head2 multiple This key specifies that the parameter may appear multiple times in the request. Without this directive, multiple values for the same parameter will generate an error. For example: $ds->define_ruleset( 'identifiers' => { param => 'id', valid => POS_VALUE, multiple => 1 }); If this directive is used, then the cleaned value of the parameter will be a list if at least one valid value was found and I otherwise. If you wish a request to be considered valid even if some of the values fail the validator, then either use the L key instead or include a L key as well. =head2 split This directive has the same effect as L, and in addition causes each parameter value string to be split (L) as indicated by the value of the directive. If this value is a string, then it will be compiled into a regexp preceded and followed by C<\s*>. So in the following example: define_ruleset( 'identifiers' => { param => 'id', valid => POS_VALUE, split => ',' }); The value string will be considered to be valid if it contains one or more positive integers separated by commas and optional whitespace. Empty strings between separators are ignored. 123,456 # returns [123, 456] 123 , ,456 # returns [123, 456] , 456 # returns [456] 123 456 # not valid 123:456 # not valid If you wish more precise control over the separator expression, you can pass a regexp quoted with L instead. =head2 list This directive has the same effect as L, but generates warnings instead of error messages when invalid values are encountered (as if C<< warn => 1 >> was also specified). The resulting cleaned value will be a list containing any values which pass the validator, or I if no valid values were found. See also L. =head2 alias This directive specifies one or more aliases for the parameter name (use a listref for multiple aliases). These names may be used interchangeably in requests, but any request that contains more than one of them will be rejected with an appropriate error message unless L is also specified. =head2 default This directive specifies a default value for the parameter, which will be reported if no value is specified in the request. If the rule also includes a validator, the specified default value will be passed to it and the resulting cleaned value, if any, will be used. An exception will be thrown at the time of rule definition if the default value does not pass the validator. =head2 no_set_doc If this directive is given a true value, then the documentation string for this rule will not have a list of set values appended. You can use this if you are giving the name of a set as a validator, but do not wish to have the list of set values automatically appended. =head1 AUTHOR mmcclenn "at" cpan.org =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 COPYRIGHT & LICENSE Copyright 2014 Michael McClennen, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut