Acme-CPANModulesBundle-Import-PerlDancerAdvent-2018

 view release on metacpan or  search on metacpan

LICENSE  view on Meta::CPAN


2. You may apply bug fixes, portability fixes and other modifications derived
from the Public Domain or from the Copyright Holder. A Package modified in such
a way shall still be considered the Standard Version.

3. You may otherwise modify your copy of this Package in any way, provided that
you insert a prominent notice in each changed file stating how and when you
changed that file, and provided that you do at least ONE of the following:

  a) place your modifications in the Public Domain or otherwise make them
     Freely Available, such as by posting said modifications to Usenet or an
     equivalent medium, or placing the modifications on a major archive site
     such as ftp.uu.net, or by allowing the Copyright Holder to include your
     modifications in the Standard Version of the Package.

  b) use the modified Package only within your corporation or organization.

  c) rename any non-standard executables so the names do not conflict with
     standard executables, which must also be provided, and provide a separate
     manual page for each non-standard executable that clearly documents how it
     differs from the Standard Version.

META.json  view on Meta::CPAN

                        "name" : "FUNCTIONS",
                        "version" : "4.015"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Leftovers",
                        "name" : "@Author::PERLANCAR/Leftovers",
                        "version" : "4.015"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Author::PERLANCAR/postlude",
                        "version" : "4.015"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Completion::GetoptLongComplete",
                        "name" : "@Author::PERLANCAR/Completion::GetoptLongComplete",
                        "version" : "0.08"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Completion::GetoptLongSubcommand",
                        "name" : "@Author::PERLANCAR/Completion::GetoptLongSubcommand",

META.yml  view on Meta::CPAN

            -
              class: Pod::Weaver::Section::Collect
              name: FUNCTIONS
              version: '4.015'
            -
              class: Pod::Weaver::Section::Leftovers
              name: '@Author::PERLANCAR/Leftovers'
              version: '4.015'
            -
              class: Pod::Weaver::Section::Region
              name: '@Author::PERLANCAR/postlude'
              version: '4.015'
            -
              class: Pod::Weaver::Section::Completion::GetoptLongComplete
              name: '@Author::PERLANCAR/Completion::GetoptLongComplete'
              version: '0.08'
            -
              class: Pod::Weaver::Section::Completion::GetoptLongSubcommand
              name: '@Author::PERLANCAR/Completion::GetoptLongSubcommand'
              version: '0.04'
            -

devdata/http_advent.perldancer.org_2018_13  view on Meta::CPAN

</div>


<div id="content">
<div class="pod-document"><h1><a name="the_twelve_days_of_dancer"></a>The Twelve Days of Dancer</h1>

<p>Hello and goodbye, 2018! It seems like we hardly knew you. It's been a few 
years since our last calendar, and while everyone here is busy with other 
projects, we still wanted to give you a mini-advent-calendar this year. 
Welcome to the Twelve Days of Dancer!</p>
<p>This year's calendar features twelve posts that cover a wide range of topics.
We feature several new authors, cover some new ground (for us!) with an
article on accessibility, and even have a crossover post showing how Dancer
can be used with other frameworks.</p>
<p>Without further ado, let's dance!</p>
<h2><a name="state_of_the_dancer"></a>State of the Dancer</h2>

<p>In 2017 and 2018, we saw fewer but more significant updates to Dancer and 
Dancer2. With Dancer (1) being in maintenance mode, updates come only when
significant bugs are found, security vulnerabilities are found, or when a 
change is proposed that greatly improve the lives of Dancer developers. 
David Precious has been the light that guides Dancer(1) through the night,
and has been an excellent resource for both the Dancer and Dancer2 communities

devdata/http_advent.perldancer.org_2018_15  view on Meta::CPAN

<h2><a name="example"></a>EXAMPLE</h2>

<p>Let me show you an example as described in the official document for <a href="https://metacpan.org/release/Dancer2-Plugin-Paginator">Dancer2::Plugin::Paginator</a>.</p>
<pre class="prettyprint">use Dancer2;
use Dancer2::Plugin::Paginator;

get '/list' =&gt; sub {
    my $paginator = paginator(
       'curr'     =&gt; $page,
       'items'    =&gt; rset('Post')-&gt;count,
       'base_url' =&gt; '/posts/page/',
    );

    template 'list', { paginator =&gt; $paginator };
};

true;</pre>

<h2><a name="configuration"></a>CONFIGURATION</h2>

<p>To bring the above example live, we need to tune the configuration slightly as below.</p>

devdata/http_advent.perldancer.org_2018_16  view on Meta::CPAN


    if( exists $minion_config-&gt;{ $hostname }) {
        return $minion_config-&gt;{ $hostname };
    } else {
        return $minion_config-&gt;{ default };
    }
}</pre>

<h2><a name="monitoring_the_workers"></a>Monitoring the Workers</h2>

<p>Our Minion dashboard was virtually identical to the one that @preaction posted in <a href="https://mojolicious.io/blog/2018/12/11/who-watches-the-minions/#section-2">Who Watches the Minions?</a>.
If you'd like to know more, I highly recommend reading his article.</p>
<h2><a name="outcome"></a>Outcome</h2>

<p>Within about a two-week timespan, we went from having zero practical knowledge of Minion to having things up and running. We've made some refinements and improvements along the way, but the quick turnaround
is a true testament to the simplicity of working with Minion.</p>
<p>We now have all the necessary pieces in place to scale our XML rendering both horizontally and vertically: thanks to Minion, we can easily run XML jobs across multiple boxes, and can more efficiently run 
more jobs concurrently on the same hardware as before. This setup allows us to grow as quickly as our customer base does.</p>
<h2><a name="author"></a>Author</h2>

<p>This article has been written by Jason Crome (CromeDome) for the Perl Dancer 

devdata/http_advent.perldancer.org_2018_17  view on Meta::CPAN

<pre class="prettyprint">email {
    from =&gt; 'foo@perl.dance',
    to =&gt; 'bar@perl.dance',
    subject =&gt; 'Hello world',
    text =&gt; 'Welcome to the dancefloor!',
};</pre>

<p>The more common case would be to use a template from your web application and turn it into a HTML email.</p>
<p>Instead of using the <code>template</code> keyword to return the HTML from your route to the browser, you generate HTML with a specific layout,
store in a variable and send the email.</p>
<pre class="prettyprint">post '/welcome' =&gt; {
      
    my $html = template $template, $tokens, { layout =&gt; 'email' };

    email {
        from =&gt; 'foo@perl.dance',
        to =&gt; 'bar@perl.dance',
        subject =&gt; 'Welcome to the dancefloor!',
        type =&gt; 'html',
        body =&gt; $html,
    }

devdata/http_advent.perldancer.org_2018_20  view on Meta::CPAN

  -&gt;status_is(200)
  -&gt;content_type_like(qr[text/plain])
  -&gt;content_is('hello santa');</pre>

<p>Moving on we request the data endpoint, both without and with a query, then similarly test the responses.</p>
<pre class="prettyprint">$t-&gt;get_ok('/data')
  -&gt;status_is(200)
  -&gt;content_type_like(qr[application/json])
  -&gt;json_is('/hello' =&gt; 'world');

$t-&gt;post_ok('/data' =&gt; form =&gt; { name =&gt; 'rudolph' })
  -&gt;status_is(200)
  -&gt;content_type_like(qr[application/json])
  -&gt;json_is('/hello' =&gt; 'rudolph');</pre>

<p>You can see we use the <code>json_is</code> method to test the responses.
Now, the test could have been <code>-&gt;json_is({hello =&gt; 'rudolph'})</code> if had wanted to test the entire document.
By passing a <a href="https://mojolicious.org/perldoc/Mojo/JSON/Pointer">JSON Pointer</a> I can inspect only the portions I'm interested in.</p>
<p>Finally I'm going to test the HTML endpoint.
As I said above, the result resists easy parsing.
We want to test the <code>dd</code> tag contents that follows a <code>dt</code> tag with the id <code>hello</code>, all inside a <code>dl</code> tag with the id <code>data</code>.
That would be a monstrous regexp (hehe).
However it is a piece of cake using <a href="https://mojolicious.org/perldoc/Mojo/DOM/CSS">CSS Selectors</a>.</p>
<pre class="prettyprint">$t-&gt;get_ok('/html')
  -&gt;status_is(200)
  -&gt;content_type_like(qr[text/html])
  -&gt;text_is('dl#data dt#hello + dd', 'world');

$t-&gt;post_ok('/html' =&gt; form =&gt; { name =&gt; 'grinch' })
  -&gt;status_is(200)
  -&gt;content_type_like(qr[text/html])
  -&gt;text_is('dl#data dt#hello + dd', 'grinch');

done_testing;</pre>

<p>In this year's Mojolicious advent calendar, we've already seen <a href="https://mojolicious.io/blog/2018/12/05/compound-selectors/">some</a> <a href="https://mojolicious.io/blog/2018/12/14/a-practical-example-of-mojo-dom/">great</a> <a href="https...
The point remains however, testing HTML responses with CSS selectors allows you to make your tests targetd in a way that allows you to write more and better tests since you don't have to hack around extracting the bits you want.</p>
<h2><a name="testing_websockets"></a>Testing WebSockets</h2>

devdata/http_advent.perldancer.org_2018_21  view on Meta::CPAN

<p>Even before I learned about the accessibility issues with CAPTCHAs, I knew adding one to my form was just
bad UX. It's shifting the burden of your problem onto your users. But when the only tool you think you possess 
is a hammer, all of your problems start to look a lot like nails.</p>
<p>The solution Job encouraged me to pursue was to have two form fields on my contact form that should never get 
filled in: one that is a standard form field, but using CSS, is visually hidden from the user, and the other is
to use a hidden form field. If any one of those fields is filled in, then you know you are dealing with a spambot,
and you can take the appropriate action.</p>
<h2><a name="backend_code"></a>Backend code</h2>

<p>Making this work in Dancer2 is really, really easy:</p>
<pre class="prettyprint">post '/contact' =&gt; sub {
    my $spam_1 = body_parameters-&gt;get( 'spam_one' );
    my $spam_2 = body_parameters-&gt;get( 'spam_two' );

    redirect 'https://en.wikipedia.org/wiki/Three_Laws_of_Robotics'
        if $spam_1 || $spam_2;

    # Ok, we seem to be a real human, so do something...
    my $contact;
    my $name    = body_parameters-&gt;get( 'name'    );
    my $email   = body_parameters-&gt;get( 'email'   );

devdata/http_advent.perldancer.org_2018_21  view on Meta::CPAN

    # - etc. etc.
};</pre>

<p>We look to see if either of the spam-catching form fields is populated. If either one of them is populated,
we educate the bot in <a href="https://en.wikipedia.org/wiki/Three_Laws_of_Robotics">Asimov's Three Laws of Robotics</a>. 
If not, we are reasonably certain we are dealing with a human, and we continue on our merry way.</p>
<h2><a name="front_end_magic"></a>Front-end magic</h2>

<p>The front end is where things get a little more interesting (note: I have deliberately omitted any styling for
the sake of brevity):</p>
<pre class="prettyprint">&lt;form method="post" action="/contact" id="contact"&gt;
    &lt;label for="name"&gt;Name&lt;/label&gt;
    &lt;input type="text" name="name" id="name" placeholder="First and last name"&gt;

    &lt;label for="email"&gt;Email Address&lt;/label&gt;
    &lt;input type="text" name="email" id="email" placeholder="someone@example.com"&gt;
        
    &lt;label for="subject"&gt;Subject&lt;/label&gt;
    &lt;input type="text" name="subject" id="subject" placeholder="Nature of inquiry?"&gt;
        
    &lt;label for="message"&gt;Message&lt;/label&gt;

devdata/http_advent.perldancer.org_2018_22  view on Meta::CPAN

    # 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'} || '';

devdata/http_advent.perldancer.org_2018_22  view on Meta::CPAN


<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>



( run in 0.850 second using v1.01-cache-2.11-cpan-ceb78f64989 )