Acme-CPANModulesBundle-Import-PerlDancerAdvent-2018
view release on metacpan or search on metacpan
devdata/http_advent.perldancer.org_2018_22 view on Meta::CPAN
<blockquote>
<p>We didn't want to create our own type system or type validations. There
are already plenty of good ones.</p>
<blockquote>
<p>And we didn't want to tie the plugin with a specific type system
because it might not suit you.</p>
</blockquote>
<p>Instead, we picked a third option: Allowing you to connect it with
whatever you want.</p>
<pre class="prettyprint">use Dancer2;
use Dancer2::Plugin::ParamTypes;
# register an 'Int'
register_type_check 'Int' => sub { $_[0] =~ /^[0-9]+$/ };</pre>
<p>You could also register existing type systems:</p>
<pre class="prettyprint">use MooX::Types::MooseLike::Base qw< Int >;
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>
( run in 0.632 second using v1.01-cache-2.11-cpan-acf6aa7dc9e )