Acme-CPANModulesBundle-Import-MojoliciousAdvent-2018

 view release on metacpan or  search on metacpan

LICENSE  view on Meta::CPAN

    you changed the files and the date of any change; and

    b) cause the whole of any work that you distribute or publish, that
    in whole or in part contains the Program or any part thereof, either
    with or without modifications, to be licensed at no charge to all
    third parties under the terms of this General Public License (except
    that you may choose to grant warranty protection to some or all
    third parties, at your option).

    c) If the modified program normally reads commands interactively when
    run, you must cause it, when started running for such interactive use
    in the simplest and most usual way, to print or display an
    announcement including an appropriate copyright notice and a notice
    that there is no warranty (or else, saying that you provide a
    warranty) and that users may redistribute the program under these
    conditions, and telling the user how to view a copy of this General
    Public License.

    d) You may charge a fee for the physical act of transferring a
    copy, and you may at your option offer warranty protection in
    exchange for a fee.

LICENSE  view on Meta::CPAN

                     END OF TERMS AND CONDITIONS

        Appendix: How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.

  To do so, attach the following notices to the program.  It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) 19yy  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 1, or (at your option)
    any later version.

LICENSE  view on Meta::CPAN

    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA


Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) 19xx name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License.  Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your

devdata/https_mojolicious.io_blog_2018_12_02_automatic-reload-for-rapid-development_  view on Meta::CPAN

              <div class="post-thumb">
                <!-- theme suggests 1300x500 -->
                <img alt="Mojolicious art and reload icon, original artwork by Doug Bell" src="/blog/2018/12/02/automatic-reload-for-rapid-development/banner.jpg">
              </div>

            <div class="post-content">

              <section id="section-1">
                  <p>Developing webapps with <a href="http://mojolicious.org">Mojolicious</a> is a lot of fun!
Using <a href="https://mojolicious.org/perldoc/morbo">the <code>morbo</code> server</a> for
development, every change to my webapp causes a restart to load my changes.
This way the next request I make has all my new code!</p>

<p>So, I change my code, the webapp restarts, and I go back to my browser window.
Wait... Where&#39;s my new code? Why isn&#39;t the bug fixed? Did... Did I forget to
reload my browser window again? Ugh! Of course!</p>

<p>Does this happen to you? Probably not. But, it&#39;s still annoying to reload the
browser window after every backend code change. It&#39;d be nice if my browser
window automatically reloaded every time the web server restarted!</p>

              </section>
              <section id="section-2">
                  <h1>AutoReload Plugin</h1>

<p>Like every problem in Perl, there&#39;s a CPAN module for this:
<a href="http://metacpan.org/pod/Mojolicious::Plugin::AutoReload">Mojolicious::Plugin::AutoReload</a>.
Adding this plugin to our application will automatically reload any browser
windows connected to our app, making it even easier to develop Mojolicious
applications!</p>

<p>To use the plugin, we add it to our application using the <code>plugin</code> method.
Then, we add the <code>auto_reload</code> helper to our <a href="https://metacpan.org/pod/distribution/Mojolicious/lib/Mojolicious/Guides/Tutorial.pod#Layouts">layout
template</a></p>

<pre><code>use Mojolicious::Lite;

plugin &#39;AutoReload&#39;;
get &#39;/&#39; =&gt; &#39;index&#39;;

app-&gt;start;
__DATA__

@@ layouts/default.html.ep
%= auto_reload
%= content

@@ index.html.ep
% layout &#39;default&#39;;
&lt;h1&gt;Hello, World!&lt;/h1&gt;
</code></pre>

<p><a href="myapp.pl">Download the code here</a>. Now while we have our application open in
our browser, if the server is restarted, our browser will reload the page to
see the new app!</p>

<h2>How It Works</h2>

<p>This plugin is sheer elegance in its simplicity: When the browser loads the
page, it connects to a WebSocket located at <code>/auto_reload</code>. When the server
restarts, the WebSocket connection is broken. The client sees the broken
connection, waits a second for the server to start listening for connections
again, and then reloads the page.</p>

<h2>Disable In Production</h2>

<p>Once we switch from <code>morbo</code> to <code>hypnotoad</code>, we don&#39;t want the automatic reload
anymore. So, the plugin doesn&#39;t send the browser the JavaScript to build the
websocket. This is controlled with <a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial#Mode">the <code>mode</code>
attribute</a>.
When the <code>mode</code> is <code>development</code> (the default for <code>morbo</code>), the browser is told
to make the WebSocket. When the <code>mode</code> is anything else, no WebSocket is made.</p>

devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_  view on Meta::CPAN

<pre><code>#!/usr/bin/env perl
use Mojolicious::Lite;
# Log exceptions to a separate log file
hook after_dispatch =&gt; sub {
    my ( $c ) = @_;
    return unless my $e = $c-&gt;stash( &#39;exception&#39; );
    state $path = $c-&gt;app-&gt;home-&gt;child(&quot;exception.log&quot;);
    state $log = Mojo::Log-&gt;new( path =&gt; $path );
    $log-&gt;error( $e );
};
app-&gt;start;
</code></pre>

<p>To test this, once I&#39;ve loaded my app and created a Test::Mojo object,
I&#39;m free to add more configuration to my app, including new routes!
These routes can set up exactly the right conditions for my test.</p>

<pre><code># test.pl
use Test::More;
use Test::Mojo;
use Mojo::File qw( path );

devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_  view on Meta::CPAN


<p>Run this with no argument and I see all the <code>img</code> tags:</p>

<pre><code>$ perl html.pl
&lt;img class=&quot;human&quot; id=&quot;farnworth &quot; src=&quot;...&quot;&gt;
&lt;img class=&quot;robot&quot; id=&quot;bender&quot; src=&quot;...&quot;&gt;
&lt;img class=&quot;human&quot; id=&quot;fry&quot; src=&quot;...&quot;&gt;
&lt;img class=&quot;mutant&quot; id=&quot;leela&quot; src=&quot;...&quot;&gt;
</code></pre>

<p>With an argument I can choose any part that I like. Here I get the parts starting with the <code>li</code> tag:</p>

<pre><code>$ perl html.pl li
&lt;li&gt;&lt;img class=&quot;robot&quot; id=&quot;bender&quot; src=&quot;...&quot;&gt;&lt;/li&gt;
&lt;li&gt;&lt;img class=&quot;human&quot; id=&quot;fry&quot; src=&quot;...&quot;&gt;&lt;/li&gt;
&lt;li&gt;&lt;img class=&quot;mutant&quot; id=&quot;leela&quot; src=&quot;...&quot;&gt;&lt;/li&gt;
</code></pre>

<p>I can select all the images with a certain class:</p>

<pre><code>$ perl html.pl img.human

devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_  view on Meta::CPAN

        my $c = substr $_, 0, 1;
        [ $c, ord($c), charnames::viacode( ord($c) ) ]
        })
    -&gt;sort( sub { $a-&gt;[1] &lt;=&gt; $b-&gt;[1] } )
    -&gt;map( sub {
        sprintf &#39;%s (U+%05X) %s&#39;, $_-&gt;@*
        } )
    -&gt;join( &quot;\n&quot; );
</code></pre>

<p>This makes a nice list that starts like this:</p>

<pre><code>🕺 (U+1F57A) MAN DANCING
🖤 (U+1F5A4) BLACK HEART
🛑 (U+1F6D1) OCTAGONAL SIGN
🛒 (U+1F6D2) SHOPPING TROLLEY
🛴 (U+1F6F4) SCOOTER
🛵 (U+1F6F5) MOTOR SCOOTER
🛶 (U+1F6F6) CANOE
</code></pre>

devdata/https_mojolicious.io_blog_2018_12_06_making-a-list-with-yancy_  view on Meta::CPAN

              <section id="section-1">
                  <p>In these modern times, with billions of people in the world, Santa needs a
modern system to keep track of his naughty/nice list. Lucky for Santa, modern
Perl has a modern web framework, <a href="http://mojolicious.org">Mojolicious</a>.</p>

              </section>
              <section id="section-2">
                  <h1>Step 1: Build The List</h1>

<p>First, we need a database schema. Santa only really needs to know if someone
has been naughty or nice, so our schema is pretty simple. We&#39;ll start our
<a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Mojolicious::Lite</a>
app by connecting to a <a href="http://sqlite.org">SQLite</a> database using
<a href="https://metacpan.org/pod/Mojo::SQLite">Mojo::SQLite</a> and loading our database
schema from the <a href="https://perldoc.perl.org/perldata.html#Special-Literals"><strong>DATA</strong> section of our
script</a> using
<a href="https://metacpan.org/pod/Mojo::SQLite::Migrations">Mojo::SQLite migrations</a>:</p>

<pre><code>use v5.28;
use Mojolicious::Lite;
use Mojo::SQLite;

# Connect to the SQLite database and load our schema from the
# &#39;@@ migrations&#39; section, below
my $db = Mojo::SQLite-&gt;new( &#39;sqlite:thelist.db&#39; );
$db-&gt;auto_migrate(1)-&gt;migrations-&gt;from_data();

# Start the app. Must be the last code of the script.
app-&gt;start;

__DATA__
@@ migrations
-- 1 up
CREATE TABLE the_list (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR NOT NULL,
    address VARCHAR NOT NULL,
    is_nice BOOLEAN DEFAULT FALSE,
    is_delivered BOOLEAN DEFAULT FALSE

devdata/https_mojolicious.io_blog_2018_12_07_openapi_  view on Meta::CPAN

<p>There are times that a property of an object might be <code>null</code>. In the MetaCPAN API the favourite count may either be an integer representing how many people have favourited the distribution, or <code>null</code>. Using a list for the pro...

<pre><code>favorites:
  type:
    - &quot;integer&quot;
    - &quot;null&quot;
</code></pre>

<h3>The MetaCPAN Specification</h3>

<p>The entire specification doesn’t need to be complete in order to get OpenAPI up and running. When documenting an existing API, it’s possible to with one portion of the API. With MetaCPAN we started with the search endpoints.</p>

<p>The <a href="https://github.com/metacpan/metacpan-api/blob/master/root/static/v1.yml">spec file can be viewed here</a> and the <a href="https://fastapi.metacpan.org/static/index.html">API documentation here</a></p>

<h2>Further Reading</h2>

<p>The <a href="https://github.com/OAI/OpenAPI-Specification">OpenAPI Specification repository</a> includes full documentation and many examples of varying levels of details.</p>

<p>The <a href="https://openapi-map.apihandyman.io">OpenAPI Map</a> is an interactive site to aid in working with the OpenAPI Specification.</p>

              </section>

devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_  view on Meta::CPAN

<a href="https://act.yapc.eu/lpw2018">London Perl Workshop</a>
in 2018.
It&#39;s a little optimistic thinking that they&#39;ll get through
editing all the videos before Christmas, but we could hope
for an epiphany.
LDAP is just a small part of the authentication cycle here, so
this post generalises fairly well for those cases where you have
to write your own credential checker.
Oh, and the talk and writing this post has done exactly what was intended
and raised issues that I hadn&#39;t considered which I&#39;ve included here.
As a result, it&#39;s starting to read like
<a href="https://en.wikipedia.org/wiki/Alice%27s_Restaurant_Massacree">Alice&#39;s Restaurant</a>
without the full orchestration and five part harmony.
I hope this cautionary tale helps you to avoid the same pitfalls that I fell into.</p>

<p>In the meantime, have a
<a href="https://www.youtube.com/watch?v=t-BEo467pUI">Lightning Talk</a>
from MojoConf 2018.</p>

<h3>Route - lib/MyApp.pm</h3>

<p>First off, a confession.  I never really got into Lite Apps.
I know it&#39;s <a href="https://www.youtube.com/watch?v=ycAXeOKLCGc">easy</a>
to <a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Growing">grow them into Full Apps</a>,
but I was under pressure to crank out a solution when I started and never got back to it.
The result is that this post is about authenticating a <strong>Full App</strong> and isn&#39;t as
svelte as the other posts talking about their Lite apps.</p>

<p>Jumping straight in, let&#39;s assume that you already have a Login page
in your templates and it has a form which posts data to <code>/login</code>.
If you&#39;ve got a route like this</p>

<pre><code>$r-&gt;post(&#39;/login&#39;)-&gt;name(&#39;do_login&#39;)-&gt;to(&#39;Secure#on_user_login&#39;);
</code></pre>

devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_  view on Meta::CPAN


<p>Pro tip: You can even simplify it to</p>

<pre><code>%= form_for &#39;do_login&#39;
</code></pre>

<p>which does it all for you including the <code>method</code> if the route only handles <code>POST</code>.</p>

<h3>Controller - lib/MyApp/Controller/Secure.pm</h3>

<p>Let&#39;s get started by cribbing from the
<a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Cookbook#Basic-authentication1">Mojolicious Cookbook</a>.</p>

<pre><code>package MyApp::Controller::Secure;
use Mojo::Base &#39;Mojolicious::Controller&#39;;

sub on_user_login {
  my $self = shift;

  my $username = $self-&gt;param(&#39;username&#39;);
  my $password = $self-&gt;param(&#39;password&#39;);

devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_  view on Meta::CPAN

}

sub check_credentials {
  my ($self, $username, $password) = @_;
...
  return $self-&gt;scrypt_verify($password, $encoded);
}
</code></pre>

<p>Y&#39;know, I&#39;m sitting here on the Group W bench thinkin&#39; ...
if I&#39;m going to re-write this whole tutorial, maybe I should&#39;ve started with
<a href="https://metacpan.org/pod/Mojolicious::Plugin::Authentication">Mojolicious::Plugin::Authentication</a>
and taken you through the code you needed for the <code>validate_user</code> option in the Plugin.
But let&#39;s leave that for next year.</p>

<p>Further reading on storing passwords:</p>

<ul>
<li><a href="https://crackstation.net/hashing-security.htm#properhashing">Secure Salted Password Hashing</a> by Defuse Security.</li>
</ul>

devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_  view on Meta::CPAN

              </section>
              <section id="section-2">
                  <p>If I don&#39;t have a large enough set of jobs to need the task organization
provided by <a href="https://metacpan.org/pod/Beam::Minion">Beam::Minion</a>, and although
Minion can be used as a <a href="https://mojolicious.org/perldoc/Minion#SYNOPSIS">fully stand-alone
library</a>, the easiest solution
is just to build a Mojolicious app. Lucky for me, a Mojolicious app can be just
2 lines:</p>

<pre><code>use Mojolicious::Lite;
app-&gt;start;
</code></pre>

<p>Now, if I never run a web daemon, this will never be a website. So, can
this be called a web application if nobody ever uses a web browser to
access it? 🤔</p>

<h2>Add Minion</h2>

<p>To use Minion, add the Minion plugin to the app. For this example, I&#39;ll
use <a href="https://metacpan.org/pod/Minion::Backend::SQLite">the SQLite Minion

devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_  view on Meta::CPAN

use Mojolicious::Lite;
use experimental qw( signatures );
use Time::HiRes qw( time );

plugin Minion =&gt; {
    SQLite =&gt; &#39;sqlite:&#39; . app-&gt;home-&gt;child(&#39;minion.db&#39;),
};

app-&gt;minion-&gt;add_task(
    check_url =&gt; sub( $job, $url ) {
        my $start = time;
        my $tx = $job-&gt;app-&gt;ua-&gt;head( $url );
        my $elapsed = time - $start;
        $job-&gt;app-&gt;log-&gt;info(
            sprintf &#39;Fetching %s took %.3f seconds&#39;, $url, $elapsed
        );
        # If there&#39;s an error loading the web page, fail the job
        if ( $tx-&gt;error ) {
            $job-&gt;app-&gt;log-&gt;error(
                sprintf &#39;Error loading URL (%s): %s (%s)&#39;,
                    $url, @{ $tx-&gt;error }{qw( code message )},
            );
            return $job-&gt;fail(
                sprintf &#39;%s: %s&#39;, @{ $tx-&gt;error }{qw( code message )}
            );
        }
        $job-&gt;finish( $elapsed );
    },
);

app-&gt;start;
</code></pre>

<h2>Enqueuing Jobs</h2>

<p>Now that I have a task, I can enqueue some jobs. I can add jobs using
<a href="https://mojolicious.org/perldoc/Minion/Command/minion/job">the <code>minion job</code>
command</a>:</p>

<pre><code>$ perl myapp.pl minion job -e check_url -a &#39;[&quot;http://mojolicious.org&quot;]&#39;
</code></pre>

devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_  view on Meta::CPAN


<h2>Running a Worker</h2>

<p>I&#39;ve enqueued jobs, but nothing&#39;s happening, and nothing will happen
until I run a worker using <a href="https://mojolicious.org/perldoc/Minion/Command/minion/worker">the <code>minion worker</code>
command</a>:</p>

<pre><code>$ perl myapp.pl minion worker
</code></pre>

<p>Once the worker starts up, it will immediately begin processing the jobs
I told it to run.</p>

<p>And that&#39;s it! I&#39;m using Minion without a Mojolicious
web application. View the source of the <a href="minion.pl">Minion app</a> and the
<a href="enqueue.pl">enqueue.pl script</a>.</p>

              </section>
              <small><p>Original artwork by Doug Bell, released under CC-BY-SA 4.0. It includes
a screenshot of the Mojolicious.org website (fair use), the Mojolicious
logo (CC-BY-SA 4.0), and the Minion logo (CC-BY-SA 4.0)</p>

devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_  view on Meta::CPAN

  &quot;delayed&quot; =&gt; &quot;2018-11-23T19:15:47Z&quot;,
  &quot;finished&quot; =&gt; &quot;2018-11-23T19:15:48Z&quot;,
  &quot;id&quot; =&gt; 1,
  &quot;notes&quot; =&gt; {},
  &quot;parents&quot; =&gt; [],
  &quot;priority&quot; =&gt; 0,
  &quot;queue&quot; =&gt; &quot;default&quot;,
  &quot;result&quot; =&gt; &quot;0.0716841220855713&quot;,
  &quot;retried&quot; =&gt; undef,
  &quot;retries&quot; =&gt; 0,
  &quot;started&quot; =&gt; &quot;2018-11-23T19:15:47Z&quot;,
  &quot;state&quot; =&gt; &quot;finished&quot;,
  &quot;task&quot; =&gt; &quot;check_url&quot;,
  &quot;worker&quot; =&gt; 1
}
</code></pre>

<p>But, it&#39;d be a lot nicer if I didn&#39;t have to open a terminal, open an
SSH connection, and run a command to look at the status of my Minion.</p>

<h2>Minion Admin UI</h2>

devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_  view on Meta::CPAN

plugin:</p>

<pre><code>use Mojolicious::Lite;
plugin Minion =&gt; {
    SQLite =&gt; &#39;sqlite:&#39; . app-&gt;home-&gt;child(&#39;minion.db&#39;),
};
plugin &#39;Minion::Admin&#39;, {
    # Host Admin UI at /
    route =&gt; app-&gt;routes-&gt;any(&#39;/&#39;),
};
app-&gt;start;
</code></pre>

<p>Once I add the plugin, I now have a web application that I can run with
the <a href="https://mojolicious.org/perldoc/Mojolicious/Command/daemon">Mojolicious <code>daemon</code>
command</a>.</p>

<pre><code>$ perl myapp.pl daemon
Server available at http://127.0.0.1:3000
</code></pre>

devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_  view on Meta::CPAN

</code></pre>

<p>To help us for future capacity planning, we want our workers to tell us if they are running at peak capacity, so log when this event occurs:</p>

<pre><code>$worker-&gt;on( busy =&gt; sub( $worker ) {
    my $max = $worker-&gt;status-&gt;{ jobs };
    $logger-&gt;log( &quot;$0: Running at capacity (performing $max jobs).&quot; );
});
</code></pre>

<p>Now, we apply the configuration (read below) to the worker. When the worker starts, it tells us information about how it was configured (this was really useful during development):</p>

<pre><code>my $max_jobs = $hostconfig-&gt;{ max_children };
my @queues   = @{ $hostconfig-&gt;{ queues }};

if( $minion-&gt;has_invalid_queues( @queues ) ){
    print &quot;Invalid job queues specified: &quot; . join( &#39;,&#39;, $minion-&gt;get_invalid_queues( @queues ) );
    say &quot;. Aborting!&quot;;
    exit 1;
}

devdata/https_mojolicious.io_blog_2018_12_13_taking-on-roles_  view on Meta::CPAN

                  <p>There are times that I want <a href="https://mojolicious.org/perldoc/Mojo/File">Mojo::File</a> to act a bit differently than it does. Often I have a path where I want to combine only the basename with a different directory. I end...

<pre><code>use Mojo::File qw(path);
my $path     = Mojo::File-&gt;new( &#39;/Users/brian/bin/interesting.txt&#39; );
my $dir      = Mojo::File-&gt;new( &#39;/usr/local/bin&#39; );
my $new_path = $dir-&gt;child( $path-&gt;basename );

say $new_path;  # /usr/local/bin/interesting.txt
</code></pre>

<p>That&#39;s annoying. I don&#39;t like that it takes so many steps. There are a few methods that I&#39;d like instead. I&#39;d rather be able to write it like this, where I start with the interesting file and keep working on it instead of switching...

<pre><code>use Mojo::File qw(path);

my $new_path = Mojo::File
    -&gt;new( &#39;/Users/brian/bin/interesting.txt&#39; )
    -&gt;rebase( &#39;/usr/local/bin&#39; );   # this isn&#39;t a method

say $new_path;  # /usr/local/bin/interesting.txt
</code></pre>

devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_  view on Meta::CPAN

toc: false
draft: false
---
This release includes a fog-flavored bauble of three equal sides, providing 
the restless digital spirits a brief respite from their painful awareness of
impermanence.

You can find the new version under the usual shadowy bridge.
</code></pre>

<p>So, to start out, I need to fetch the old site. I could have bothered the old maintainer of the site about it and gotten the original sources, but I decided just to fetch them from the web. One option would be to use wget or curl; the stuff we do ...

<pre><code>use Mojo::UserAgent;

my $url = &#39;intro&#39;;
my $ua  = Mojo::UserAgent-&gt;new;
my $tx = $ua-&gt;get(&quot;example.tld/$url.html&quot;);
</code></pre>

<p>That&#39;s it! We just fetched a web page. You might be tempted to print out $tx to see what&#39;s in it (that&#39;s what I did, rather than reading the docs, at first). But, it&#39;s a <a href="https://mojolicious.org/perldoc/Mojo/Transaction/HTT...

devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_  view on Meta::CPAN

&lt;/p&gt;
&lt;p class=&quot;post-footer align-right&quot;&gt;
&lt;span class=&quot;date&quot;&gt;November 30, 2018&lt;/span&gt;
&lt;/p&gt;
</code></pre>

<p>Notice that the structure of this is regular but not selectable with any one div or piece of markup. I can use the selector <code>h3</code> to get the headings, but the text of each news item is just a paragraph, and we also want to grab the date ...

<p>So, I want to grab all of the titles, and the paragraph following the title, and the date, and put them all into some sort of data structure so I can spit them out into pages of their own.</p>

<p>Let&#39;s start with the titles, as it&#39;ll show a neat trick Mojo has up its sleeves.</p>

<pre><code>my $main = $tx-&gt;res-&gt;dom-&gt;at(&#39;#main&#39;);
my @headers = $main-&gt;find(&#39;h3&#39;)-&gt;map(&#39;text&#39;)-&gt;each;
</code></pre>

<p>Do you see it? The <code>find</code> method here is returning a <a href="https://mojolicious.org/perldoc/Mojo/Collection">Mojo::Collection</a>. &quot;Collection&quot; is kind of a fancy way to say &quot;list&quot;, but these lists have a bunch of ...

<p>After this, <code>@headers</code> will contain all of the titles. There&#39;s no way I could do that as simply with regexes (and, we could have chained all of this, including finding <code>#main</code>, into one line, but I&#39;m re-using <code>#m...

<p>Now, an even trickier thing to do with regexes would be to find the immediately subsequent sibling of these headers. But, with Mojo::DOM, we can grab it with just a few more lines of code (there&#39;s probably a way to do it with even less code, b...

devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_  view on Meta::CPAN

<p><img class="pull-right" src="speedtest_before_StaticCache.png"></p>

<p>The magpies in the forest had cluttered the calendar with 3 JavaScript libraries,
3 CSS files and 4 logos.  Sure, the biggest and shiniest was only 66 kB
and the whole collection was a paltry 164 kB, but bandwidth is precious in the wilderness.
Before using the StaticCache plugin, the calendar rated a
<strong>92</strong> on Google&#39;s PageSpeed Insights.</p>

<p>With the StaticCache plugin loaded</p>

<pre><code>sub startup {
    my $self = shift;

    $self-&gt;plugin(&#39;StaticCache&#39; =&gt; { even_in_dev =&gt; 1 });
    ...
}
</code></pre>

<p><img class="pull-left" src="speedtest_with_StaticCache.png"></p>

<p>page speeds are now <strong>93</strong> <strong>!!!!</strong>

devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_  view on Meta::CPAN

<pre><code>#!/usr/bin/env perl
use Mojolicious::Lite;
use Mojo::SQLite;
helper db =&gt; sub {
    state $db = Mojo::SQLite-&gt;new( &#39;sqlite:&#39; . app-&gt;home-&gt;child( &#39;docs.db&#39; ) );
    return $db;
};
app-&gt;db-&gt;auto_migrate(1)-&gt;migrations-&gt;from_data();

# Start the app. Must be the code of the script
app-&gt;start;

__DATA__
@@ migrations
-- 1 up
CREATE TABLE pages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    path VARCHAR UNIQUE NOT NULL,
    markdown TEXT,
    html TEXT
);

devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_  view on Meta::CPAN

                markdown =&gt; {
                    format =&gt; &#39;markdown&#39;,
                    &#39;x-html-field&#39; =&gt; &#39;html&#39;,
                },
            },
        },
    },
};
</code></pre>

<p>Now we can create some pages. I can start up the app with <code>perl myapp.pl
daemon</code>, and then edit my content by visiting
<code>http://127.0.0.1:3000/yancy</code>. The site will especially need an index
page, so I&#39;ll create one.</p>

<p><img alt="Screenshot showing the Yancy editor adding an &quot;index&quot;
page" src="edit-index.png">
<img alt="Screenshot showing the Yancy editor listing the index page in the
database" src="list-index.png"></p>

<p>With our content created, I need to add a route to display it. Using the

devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_  view on Meta::CPAN

<a href="http://getbootstrap.com">Bootstrap</a> to make things look a bit nicer.</p>

<pre><code>get &#39;/*id&#39; =&gt; {
    id =&gt; &#39;index&#39;, # Default to index page
    controller =&gt; &#39;yancy&#39;,
    action =&gt; &#39;get&#39;,
    collection =&gt; &#39;pages&#39;,
    template =&gt; &#39;pages&#39;,
};
# Start the app. Must be the last code of the script
app-&gt;start;
__DATA__
@@ pages.html.ep
% layout &#39;default&#39;;
%== $item-&gt;{html}

@@ layouts/default.html.ep
&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;/yancy/bootstrap.css&quot;&gt;

devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_  view on Meta::CPAN

        %= javascript &#39;/yancy/bootstrap.js&#39;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>Now I can open my website and see the index page I created!</p>

<p><img alt="Screenshot showing the index page for the site" src="view-index.png"></p>

<p>Now I have a basic website! <a href="myapp.pl">Here&#39;s the code so far</a>. This is
a good start, but I&#39;ll need more if it&#39;s going to be useful...</p>

              </section>
              <small><p>Banner image CC0 Public Domain</p>
</small>

              <p class="tags">
                <span>Tagged in </span>:
                  <a href="/blog/tag/advent/">advent</a>,
                  <a href="/blog/tag/yancy/">yancy</a>
              </p>

devdata/https_mojolicious.io_blog_2018_12_18_a-view-to-a-pod_  view on Meta::CPAN

plugin (a fork of the now-deprecated
<a href="http://mojolicious.org/perldoc/Mojolicious/Plugin/PODRenderer">PODRenderer</a>
plugin).</p>

              </section>
              <section id="section-2">
                  <p>Adding PODViewer to the existing site is easy!</p>

<pre><code>use Mojolicious::Lite;
plugin &#39;PODViewer&#39;;
app-&gt;start;
</code></pre>

<p>Now when I visit <a href="http://127.0.0.1:3000/perldoc">http://127.0.0.1:3000/perldoc</a> I see the POD for
<a href="http://mojolicious.org/perldoc">Mojolicious::Guides</a>. That&#39;s great and
all, but this is a documentation site for Yancy, not Mojolicious. Let&#39;s
adjust some configuration to make the default module Yancy, and only
allow viewing Yancy modules (trying to view another module will redirect
the user to <a href="http://metacpan.org">MetaCPAN</a>).</p>

<pre><code>use Mojolicious::Lite;
plugin &#39;PODViewer&#39;, {
    default_module =&gt; &#39;Yancy&#39;,
    allow_modules =&gt; [qw( Yancy Mojolicious::Plugin::Yancy )],
};
app-&gt;start;
</code></pre>

<p>There, now the Yancy docs are shown on the front page.</p>

<p><img alt="Screenshot of Yancy module documenation" src="okay-docs.png"></p>

<p>Finally, let&#39;s make it look a bit nicer: The documentation definitely
needs to use the default site layout, and a little additional CSS will
also make the documentation look a lot better!</p>

<pre><code>use Mojolicious::Lite;
plugin &#39;PODViewer&#39;, {
    default_module =&gt; &#39;Yancy&#39;,
    allow_modules =&gt; [qw( Yancy Mojolicious::Plugin::Yancy )],
    layout =&gt; &#39;default&#39;,
};
app-&gt;start;
__DATA__
@@ layouts/default.html.ep
&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;/yancy/bootstrap.css&quot;&gt;
        &lt;style&gt;
            h1 { font-size: 2.00rem }
            h2 { font-size: 1.75rem }
            h3 { font-size: 1.50rem }

devdata/https_mojolicious.io_blog_2018_12_19_you-only-export-twice_  view on Meta::CPAN


<p>The best part is that the export command handles redirects. So, when we&#39;re
using <a href="http://metacpan.org/pod/Mojolicious::Plugin::PODViewer">the PODViewer
plugin</a> and get
redirected to <a href="http://metacpan.org">MetaCPAN</a>, the page gets updated with the
redirected location!</p>

<p>In the future it&#39;d be nice if this command were made into a plugin so that it
could have hooks for customizing the exported content or additional checks for
broken links. If anyone is interested in helping out with this work, let me
know and I can help get them started!</p>

<p>Now, with <a href="http://preaction.me/yancy">the Yancy CMS</a>, <a href="http://metacpan.org/pod/Mojolicious::Plugin::PODViewer">the PODViewer
plugin</a>, and <a href="http://metacpan.org/pod/Mojolicious::Command::export">the
Mojolicious export
command</a>, I&#39;ve got a
good-looking documentation website for Yancy! <a href="https://github.com/MojoliciousDotIO/mojolicious.io/blob/master/blog/2018/12/19/you-only-export-twice/myapp.pl">View the full, completed
application</a>.</p>

              </section>
              <small><p>Banner image CC0 Public Domain</p>

devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_  view on Meta::CPAN


<p>I expect there are at least a few of you out there who read that and think, &quot;I&#39;d love to use that, but I don&#39;t use Mojolicious!&quot;; well, you&#39;re in luck!
With just a little role to bridge the gap, you can use Test::Mojo to test your PSGI applications too!</p>

              </section>
              <section id="section-2">
                  <h2>Mounting PSGI Applications</h2>

<p>Mojolicious itself doesn&#39;t use the <a href="https://metacpan.org/pod/PSGI">PSGI</a> protocol, owing to certain features that it doesn&#39;t provide and which are necessary for certain asynchronous operations.
That said, you can serve a Mojolicious application on a PSGI server by using <a href="https://mojolicious.org/perldoc/Mojo/Server/PSGI">Mojo::Server::PSGI</a>.
This Mojolicious-core module is automatically used for you when your Mojolicious-based app detects that it has started under a PSGI server (e.g. plackup or Starman).</p>

<p>While translating between a Mojo app and a PSGI server is core functionality, doing the opposite, translating between a PSGI app and a Mojolicious server (or app, as you&#39;ll see) is available as a third party module.
<a href="https://metacpan.org/pod/Mojolicious::Plugin::MountPSGI">Mojolicious::Plugin::MountPSGI</a>, as it&#39;s name implies, can mount a PSGI application into a Mojolicious-based one.
To do so, it builds a new, empty Mojolicious application that translates all requests to PSGI environments before dispatching to it as with any <a href="https://mojolicious.org/perldoc/Mojolicious/Plugin/Mount">mount</a>-ed application.</p>

<h2>Testing using Test::Mojo</h2>

<p>Once you can do that, it is trivial to take a PSGI application, wrap it with MountPSGI, and set it as the application for use with Test::Mojo.
Still, to make it even easier, that has all been done for you in <a href="https://metacpan.org/pod/Test::Mojo::Role::PSGI">Test::Mojo::Role::PSGI</a>.</p>

devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_  view on Meta::CPAN

any &#39;/data&#39; =&gt; sub {
  my $name = param(&#39;name&#39;) // &#39;world&#39;;
  send_as JSON =&gt; { hello =&gt; $name };
};

any &#39;/html&#39; =&gt; sub {
  my $name = param(&#39;name&#39;) // &#39;world&#39;;
  template &#39;hello&#39; =&gt; { name =&gt; $name };
};

start;
</code></pre>

<p>And the template (<code>hello.tt</code>) is</p>

<pre><code>&lt;dl id=&quot;data&quot;&gt;
  &lt;dt id=&quot;hello&quot;&gt;hello&lt;/dt&gt;
  &lt;dd&gt;&lt;% name %&gt;&lt;/dd&gt;
&lt;/dl&gt;
</code></pre>

<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl">dl</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt">dt</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd">dd</a> tags...
The HTML I&#39;ve built, while nice for display isn&#39;t necessarily nice for querying programmatically, this is on purpose for the example.</p>

<h2>The Tests</h2>

<p>Of course we could start the application with <a href="https://metacpan.org/pod/distribution/Plack/script/plackup"><code>plackup</code></a> but that&#39;s not what we&#39;re trying to do.
I&#39;ll break the test script down a bit but if you want to see any of these files look at the <a href="https://github.com/MojoliciousDotIO/mojolicious.io/tree/master/blog/2018/12/20/testing-dancer/ex">blog repo</a> for a full listing.
Instead, let&#39;s load this into a test script.</p>

<pre><code>use Mojo::Base -strict;
</code></pre>

<p>Now if you aren&#39;t familiar, <code>use Mojo::Base -strict</code> is a quick way to say</p>

<pre><code>use strict;
use warnings;

devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_  view on Meta::CPAN

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&#39;t have to hack around extracting the bits you want.</p>

<h2>Testing WebSockets</h2>

<p>Ok so that&#39;s great and all, but of course now it comes to the point you&#39;ve all been waiting for: can you test WebSockets?
As Jason Crome mentioned in his <a href="http://advent.perldancer.org/2018/13">Twelve Days of Dancer</a> &quot;State of Dancer&quot;, you can now dance with WebSockets via <a href="https://metacpan.org/pod/Dancer2::Plugin::WebSocket">Dancer2::Plugin:...

<p>Well, so far not via the role I showed above.
It might be possible, but it would involve learning deep PSGI magick that I&#39;m not sure I&#39;m smart enough to do; patches welcome obviously :D.</p>

<p>Still I mentioned above that Test::Mojo can test anything it can access via an fully qualified URL, so let&#39;s just start up a server and test it!
I&#39;ll use the <a href="https://github.com/yanick/Dancer2-Plugin-WebSocket/tree/releases/example">example bundled with the plugin</a> for simplicty.</p>

<pre><code>use Mojo::Base -strict;

use EV;
use Test::More;
use Test::Mojo;

use Twiggy::Server;
use Plack::Util;

devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_  view on Meta::CPAN

my $twiggy = Twiggy::Server-&gt;new(
  host =&gt; &#39;127.0.0.1&#39;,
  server_ready =&gt; sub {
    my $args = shift;
    $url = &quot;ws://$args-&gt;{host}:$args-&gt;{port}/ws&quot;;
  },
);
$twiggy-&gt;register_service($app);
</code></pre>

<p>This starts Twiggy bound to localhost on a random port and starts the application using it.
When the server starts, the actual host and port are passed to the <code>server_ready</code> callback which we use to build the test url.
Now you just create a Test::Mojo instance as normal but this time open a websocket to the fully-qualified url that we built above.</p>

<pre><code>my $t = Test::Mojo-&gt;new;

$t-&gt;websocket_ok($url)
  -&gt;send_ok({json =&gt; {hello =&gt; &#39;Dancer&#39;}})
  -&gt;message_ok
  -&gt;json_message_is({hello =&gt; &#39;browser!&#39;})
  -&gt;finish_ok;

devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_  view on Meta::CPAN


foreach my $file ( @ARGV ) {
    Mojo::File
        -&gt;new( $file =~ s/\.ep\z//r )
        -&gt;spurt(
            $mt-&gt;render_file( $file, { time =&gt; $now-&gt;hms } )
            );
    }
</code></pre>

<p>Now that you know everything about Mojo templates, you can process a directory full of them to start a new project:</p>

<pre><code>use v5.14;
use File::Find qw(find);
use Time::Piece;

use Mojo::File;
use Mojo::Template;

my $mt = Mojo::Template-&gt;new-&gt;vars(1);

devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_  view on Meta::CPAN

<p>Per default, <code>carton install</code> will install all the <em>features</em> dependencies, but we can deactivate some:</p>

<pre><code>carton install --deployment --without mysql
</code></pre>

<p>In order to provide the correct version for all modules, even the optional ones, do a <code>carton install</code> on the development server, and use <code>--without</code> (note that this isn&#39;t <code>--without-feature</code> like <code>cpanm</...

<h3>Start your application</h3>

<p>In order to be able to use the <code>local</code> directory containing the dependencies, you can prefix your commands with <code>carton exec</code>.
So, to start a Mojolicious application with the built-in server <a href="https://mojolicious.org/perldoc/Mojo/Server/Hypnotoad">hypnotoad</a>, do:</p>

<pre><code>carton exec -- hypnotoad script/my_application
</code></pre>

<p>That works for all that you can do with your application. Example:</p>

<pre><code>carton exec -- script/my_application routes
</code></pre>

<p>Note the two dashes: they avoid carton to interpret arguments passed to the script.

devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_  view on Meta::CPAN

<pre><code>carton install --cached
</code></pre>

<p>Combined with <code>--deployment</code> option, you can avoid querying for a database like CPAN Meta DB or downloading files from CPAN mirrors.</p>

<p>You may even avoid the need to install Carton on the production server,</p>

<pre><code>cpanm -L local --from &quot;$PWD/vendor/cache&quot; --installdeps --notest --quiet .
</code></pre>

<p>but then you will need to add the <code>local/lib/perl5</code> directory to <code>@INC</code> to start your application, since you can’t use <code>carton exec</code>.
You can do so using the core <a href="https://metacpan.org/pod/lib">lib</a> module, the handy <a href="https://metacpan.org/pod/lib::relative">lib::relative</a> from CPAN, <a href="https://perldoc.pl/perlrun#PERL5LIB">PERL5LIB</a> environment variabl...

<h2>Conclusion</h2>

<p>Carton and cpanfile are a great way to ease Mojolicious apps deployment.
Not only it avoids to list all the dependencies needed by your application in the README or the INSTALL file, but it speeds up deployments and make them more safer, since it sure lowers the risks of bugs due to bad versions of dependencies.</p>

<p><small id="footnote-1">1: or INSTALL, or wherever you put your installation documentation <a href="#back-to-1">↩️</a><small></small></small></p>

              </section>

devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_  view on Meta::CPAN

  [write] /Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/t/basic.t
  [mkdir] /Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/public
  [write] /Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/public/index.html
  [mkdir] /Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/templates/layouts
  [write] /Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/templates/layouts/default.html.ep
  [mkdir] /Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/templates/example
  [write] /Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/templates/example/welcome.html.ep
Sachin@01:07 PM[~/workspace/project/mojo_angular]$
</code></pre>

<p>Now that the Mojolicious full-app is created, start <a href="https://mojolicious.org/perldoc/Mojo/Server/Hypnotoad">hypnotoad</a>, a production web server.</p>

<pre><code>Sachin@01:07 PM[~/workspace/project/mojo_angular]$ cd mojo_angular_app/
Sachin@01:08 PM[~/workspace/project/mojo_angular/mojo_angular_app]$ hypnotoad -f script/mojo_angular_app
[Sat Dec 15 13:08:52 2018] [info] Listening at &quot;http://*:8080&quot;
Server available at http://127.0.0.1:8080
[Sat Dec 15 13:08:52 2018] [info] Manager 38209 started
[Sat Dec 15 13:08:52 2018] [info] Creating process id file &quot;/Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/script/hypnotoad.pid&quot;
[Sat Dec 15 13:08:52 2018] [info] Worker 38210 started
[Sat Dec 15 13:08:52 2018] [info] Worker 38211 started
[Sat Dec 15 13:08:52 2018] [info] Worker 38213 started
[Sat Dec 15 13:08:52 2018] [info] Worker 38212 started
</code></pre>

<p>Let&#39;s open browser and have a look at our mojo app.</p>

<p><img alt="basic Mojolicious full app" src="mojo_app.png"></p>

<h2>Generate Angular App</h2>

<p>Angular Version 7 is used for this demo, but should work for versions back to 4+. Demos on how to install Angular and CLI will be way too boring for this blog and there are plenty of resources for this in internet.</p>

devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_  view on Meta::CPAN

CREATE NgDemo/README.md (1023 bytes)
CREATE NgDemo/angular.json (3768 bytes)
CREATE NgDemo/package.json (1306 bytes)
...

Sachin@01:20 PM[~/workspace/project/mojo_angular]$ cd NgDemo/
Sachin@01:20 PM[~/workspace/project/mojo_angular/NgDemo]$ ls
README.md         angular.json      e2e               node_modules      package-lock.json package.json      src               tsconfig.json     tslint.json
</code></pre>

<p>Now for the moment, let&#39;s start the built-in angular server with <code>ng serve</code> command.</p>

<pre><code>Sachin@01:20 PM[~/workspace/project/mojo_angular/NgDemo]$ ng serve
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **

Date: 2018-12-15T05:22:00.337Z
Hash: c05a16d8553980a82a62
Time: 36103ms
chunk {main} main.js, main.js.map (main) 11.5 kB [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 223 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.08 kB [entry] [rendered]

devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_  view on Meta::CPAN

Sachin@02:10 PM[~/workspace/project/mojo_angular/NgDemo]$
</code></pre>

<p>Next, we&#39;ll copy everything within the folder dist/ to a folder on the <code>public</code> directory in Mojolicious app.
The Mojo full app consists of <code>public</code> directory which is a static file directory (served automatically).
Copy Angular app compiled into <code>dist</code> to <code>public</code> directory of mojo app so that mojo will serve automatically.</p>

<pre><code>Sachin@02:13 PM[~/workspace/project/mojo_angular/NgDemo]$ cp dist/NgDemo ~/workspace/project/mojo_angular/mojo_angular_app/public/
</code></pre>

<p>Of course if this were a proper project, you could generate it to build in the public directory, or even build at start time using something like <a href="https://metacpan.org/pod/Mojolicious::Plugin::AssetPack">Mojolicious::Plugin::AssetPack</a>....

<p>Finally, let&#39;s run the Mojo (hypnotoad) server to see if the Angular page is served as it was from the Angular server.</p>

<pre><code>Sachin@02:48 PM[~/workspace/project/mojo_angular/mojo_angular_app]$ hypnotoad -f script/mojo_angular_app
[Sat Dec 15 14:49:03 2018] [info] Listening at &quot;http://*:8080&quot;
Server available at http://127.0.0.1:8080
[Sat Dec 15 14:49:03 2018] [info] Manager 40633 started
[Sat Dec 15 14:49:03 2018] [info] Creating process id file &quot;/Users/Sachin/workspace/project/mojo_angular/mojo_angular_app/script/hypnotoad.pid&quot;
[Sat Dec 15 14:49:03 2018] [info] Worker 40634 started
[Sat Dec 15 14:49:03 2018] [info] Worker 40635 started
[Sat Dec 15 14:49:03 2018] [info] Worker 40637 started
[Sat Dec 15 14:49:03 2018] [info] Worker 40636 started
</code></pre>

<p><img alt="mojolicious serving angular SPA" src="mojo_serving_angular.png"></p>

<p>Congratulations! we have served angular app with Mojolicious. Please note that the URL will be <code>http://localhost:8080/NgDemo/</code>.</p>

<h2>Integrating the Apps Further</h2>

<p>To show how the applications can interact, we&#39;ll now build a simple demo to show an api call to a Mojolicious backend routes from the Angular frontend and display the result in Angular.
Since, this is not an Angular blog I will not go too deep explaining Angular; there are plenty of resources in internet for that.</p>

devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_  view on Meta::CPAN

use Mojo::Util &#39;trim&#39;;
my $ua = Mojo::UserAgent-&gt;new;
my $url = &#39;https://mojolicious.org&#39;;

my $title;
$ua-&gt;get($url, sub ($ua, $tx) {
  $title = trim $tx-&gt;res-&gt;dom-&gt;at(&#39;title&#39;)-&gt;text;
});
say $title;

Mojo::IOLoop-&gt;start;
</code></pre>

<p>The problem of course is, the print statement happens before the title is extracted.
In fact the print statement happens before the request is even made!</p>

<p><em>Because there are a lot of examples, I&#39;ll skip the first chunk of code.
Assume those lines are always there going foward.</em></p>

<p>The fix in this case is easy</p>

<pre><code>$ua-&gt;get($url, sub ($ua, $tx) {
  my $title = trim $tx-&gt;res-&gt;dom-&gt;at(&#39;title&#39;)-&gt;text;
  say $title;
});
Mojo::IOLoop-&gt;start;
</code></pre>

<p>but that isn&#39;t always the case.
What if you wanted to return the title rather than print it?
What if wanted to fetch two resources rather than one, whether sequentially or in parallel?</p>

<h2>An Important First Step</h2>

<p>Several attempts have been made to organize and improve this situation.
The pattern that seems to have emerged as the preferred choice is <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises">Promises</a>.</p>

<p>Promises have a nice property that gets them closer to linear code.
You create and return a promise object that represents the eventual result of the task, though the task itself may not have even started yet.
In our example before we could say</p>

<pre><code>use Mojo::Promise;

my $promise = Mojo::Promise-&gt;new;
$ua-&gt;get($url, sub ($ua, $tx) {
  my $title = trim $tx-&gt;res-&gt;dom-&gt;at(&#39;title&#39;)-&gt;text;
  $promise-&gt;resolve($title);
});

$promise-&gt;then(sub ($title) {
  say $title;
})-&gt;wait;
</code></pre>

<p>At first glance this isn&#39;t too much better than the callback.
However, a few nice features emerge.
The most important of which is that the promise object can be returned to the caller and the caller can choose what to do with it.</p>

<p>In useful code you would also want to attach error handling, though I&#39;ve omitted it here for bevity.
Mojolicious&#39; promise implementation also gives us the <code>wait</code> method to start the ioloop if necessary.</p>

<p>Although it is interesting to see how a user can create a promise object to convert a callback api to promises, many libraries, including Mojolicious, now have promise variants built-in.
Rather than depending on the user to create a promise to resolve in the callback, these libraries will just return a promise of their own.
In the Mojolicious project, by convention methods that return promises end in <code>_p</code>.</p>

<p>With that we can write similar code to the one above</p>

<pre><code>my $promise = $ua-&gt;get_p($url);

$promise-&gt;then(sub ($tx) {

devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_  view on Meta::CPAN

  return trim $tx-&gt;res-&gt;dom-&gt;at(&#39;title&#39;)-&gt;text;
};

any &#39;/&#39; =&gt; async sub ($c) {
  my $urls = $c-&gt;every_param(&#39;url&#39;);
  my @promises = map { $c-&gt;get_title_p($_) } @$urls;
  my @titles = await Mojo::Promise-&gt;all(@promises);
  $c-&gt;render(json =&gt; [ map { $_-&gt;[0] } @titles ]);
};

app-&gt;start;
</code></pre>

<p>Where the example above would be at</p>

<pre><code>localhost:3000?url=https%3A%2F%2Fmojolicious.org&amp;url=https%3A%2F%2Fmojolicious.io&amp;url=https%3A%2F%2Fmetacpan.org
</code></pre>

<p>That code is almost exactly what you&#39;d write for a blocking implementation except that it would block the server and it have to fetch the urls sequentially.
Instead, since it is written nonblocking, the requests are all made concurrently and the server is still free to respond to new clients.
And yet the code is still very easy to follow.</p>



( run in 0.325 second using v1.01-cache-2.11-cpan-0d8aa00de5b )