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' =&gt; sub { $_[0] =~ /^[0-9]+$/ };</pre>

<p>You could also register existing type systems:</p>
<pre class="prettyprint">use MooX::Types::MooseLike::Base qw&lt; Int &gt;;
reigster_type_checks(
    'Int' =&gt; sub { Int()-&gt;( $_[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' =&gt; with_types [
                 [ 'route', 'id', 'Int' ],
    'optional =&gt; [ 'query', 'action', 'Str' ],
] =&gt; sub {
    my $id = route_parameters-&gt;{'id'};

    # do something with $id because we know it exists and validated

    if ( my $action = query_parameters-&gt;{'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-&gt;SUPER::with_types(@_);
}

# Register all of our own type checks at build time
sub BUILD {
    my $self = shift;

    $self-&gt;register_type_check 'Str'         =&gt; sub {...};
    $self-&gt;register_type_check 'ShortStr'    =&gt; sub {...};
    $self-&gt;register_type_check 'PositiveInt' =&gt; sub {...};
    $self-&gt;register_type_check 'SHA1'        =&gt; 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' =&gt; with_types [
    [ 'route', 'entity',  'Str'         ],
    [ 'route', 'id',      'PositiveInt' ],
    [ 'body',  'message', 'Str'         ],

    'optional' =&gt; [ 'body', 'sid', 'SHA1' ],
] =&gt; sub {
    my ( $entity, $id ) = @{ route_parameters() }{qw&lt; id entity &gt;};
    my $message = body_parameters-&gt;{'message'};
    my $sid     = body_parameters-&gt;{'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' ] =&gt; '/:entity/:id' =&gt; with_types [
    [ 'route',             'entity', 'Str' ],
    [ 'route',             'id',     'PositiveInt' ],
    [ [ 'query', 'body' ], 'format', 'Str' ],

    'optional' =&gt; [ 'body', 'sid', 'SHA1' ],
] =&gt; 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 )