Acme-CPANModulesBundle-Import-PerlDancerAdvent-2018
view release on metacpan or search on metacpan
devdata/http_advent.perldancer.org_2018_22 view on Meta::CPAN
reigster_type_checks(
'Int' => sub { Int()->( $_[0] ) },
);</pre>
</blockquote>
<h3><a name="using_your_now_available_types"></a>Using your now-available types</h3>
<p>Once you register all the types you want, you could use them in your
code with a simple stanza.</p>
<pre class="prettyprint">use Dancer2::Plugin::ParamTypes;
register_type_check(...);
# Indented to make it more readable
get '/:id' => with_types [
[ 'route', 'id', 'Int' ],
'optional => [ 'query', 'action', 'Str' ],
] => sub {
my $id = route_parameters->{'id'};
# do something with $id because we know it exists and validated
if ( my $action = query_parameters->{'action'} ) {
# if it exists, we know it's validated
}
};</pre>
<h2><a name="reusability__reusability__reusability"></a>Reusability, reusability, reusability</h2>
<p><a href="https://metacpan.org/module/Dancer2::Plugin::ParamTypes">Dancer2::Plugin::ParamTypes</a> was built with a company code-abase in
mind, where you would like to have common types available. You could
easily accomplish that by subclassing it.</p>
<pre class="prettyprint">package Dancer2::Plugin::MyCommonTypes;
use Dancer2::Plugin;
# Subclass the main plugin
extends('Dancer2::Plugin::ParamTypes');
# Provide your own 'with_types' keyword
plugin_keywords('with_types');
# Make our keyword call the parent plugin
sub with_types {
my $self = shift;
return $self->SUPER::with_types(@_);
}
# Register all of our own type checks at build time
sub BUILD {
my $self = shift;
$self->register_type_check 'Str' => sub {...};
$self->register_type_check 'ShortStr' => sub {...};
$self->register_type_check 'PositiveInt' => sub {...};
$self->register_type_check 'SHA1' => sub {...};
# Maybe more?
...
}</pre>
<p>Now we have our own plugin that also provides <code>with_types</code> which uses
the original plugin with a set of registered type checks.</p>
<pre class="prettyprint">package MyApp;
use Dancer2;
use Dancer2::Plugin::MyCommonTypes;
post '/:entity/update/:id' => with_types [
[ 'route', 'entity', 'Str' ],
[ 'route', 'id', 'PositiveInt' ],
[ 'body', 'message', 'Str' ],
'optional' => [ 'body', 'sid', 'SHA1' ],
] => sub {
my ( $entity, $id ) = @{ route_parameters() }{qw< id entity >};
my $message = body_parameters->{'message'};
my $sid = body_parameters->{'sid'} || '';
# everything is validated and required parameters are checked
...
};</pre>
<h2><a name="could_i_do_more_with_it"></a>Could I do more with it?</h2>
<p>Absolutely!</p>
<h3><a name="handle_multiple_sources"></a>Handle multiple sources</h3>
<p>Normally, you would dictate to a user how they should send their
paramters (in the query, in the body, or as part of the path - in the
route), but sometimes you cannot control this. Maybe you're maintaining
an old interface or supporting outdated APIs.</p>
<p><a href="https://metacpan.org/module/Dancer2::Plugin::ParamTypes">Dancer2::Plugin::ParamTypes</a> is flexible enough to support multiple
sources for an argument:</p>
<pre class="prettyprint">any [ 'get', 'post' ] => '/:entity/:id' => with_types [
[ 'route', 'entity', 'Str' ],
[ 'route', 'id', 'PositiveInt' ],
[ [ 'query', 'body' ], 'format', 'Str' ],
'optional' => [ 'body', 'sid', 'SHA1' ],
] => sub {...};</pre>
<p>In this form, the parameter <code>format</code> can be provided either in the
query string or in the body, because your route might be either a
<b>GET</b> or a <b>POST</b>.</p>
<h3><a name="register_type_actions"></a>Register type actions</h3>
<p>Type checking itself is the main role of this plugin, but you can also
control how it behaves.</p>
<p>The default action to perform when a type check fails is to error out,
but you can decide to act differently by registering a different
action.</p>
<pre class="prettyprint">register_type_action 'SoftError' => sub {
my ( $self, $details ) = @_;
warning "Parameter $details->{'name'} from $details->{'source'} "
. "failed checking for type $details->{'type'}, called "
. "action $details->{'action'}";
return;
};
get '/:id' => with_types [
[ 'query', 'age', 'Int', 'SoftError',
( run in 1.023 second using v1.01-cache-2.11-cpan-39bf76dae61 )