view release on metacpan or search on metacpan
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.
"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",
-
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/https_mojolicious.io_blog_2017_12_01_day-1-getting-started view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 1: Getting Started</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-01">Dec 1, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="hot air ballons" src="/blog/2017/12/01/day-1-getting-started/1280px-Colorado_Springs_Hot_Air_Balloon_Competition.jpg">
</div>
<div class="post-content">
<section id="section-1">
<h2>Start at the Beginning</h2>
<p>In this Advent Calendar series, some posts will be introductory, some will be advanced, some will be on new features.
Who knows what could be next?
But for now let's ensure a level playing field by working out how to get started.</p>
</section>
<section id="section-2">
<h2>What is Mojolicious?</h2>
<p>Well, <a href="http://mojolicious.org">Mojolicious</a> is really two things.
First it is a powerful web-focused toolkit called Mojo.
Second it is a powerful web framework called Mojolicious.
devdata/https_mojolicious.io_blog_2017_12_01_day-1-getting-started view on Meta::CPAN
<ul>
<li>imports Mojolicious (the lite version)</li>
<li>defines a GET handler to respond to requests with a unicode version of hello world</li>
<li>starts the application</li>
</ul>
<p>But before that's any use to us, we have to start a web server.</p>
<h2>Running Your Application</h2>
<p>Mojolicious applications (as we'll see in another post) are more than just web servers.
In order to use them as one, we need to start it as a web server.</p>
<p>Mojolicious comes with four built-in servers</p>
<ul>
<li><code>daemon</code>, single-threaded, the basis of all the others</li>
<li><code>morbo</code>, the development server, restarts on files changes</li>
<li><code>prefork</code>, optimized production server</li>
<li><code>hypnotoad</code>, like prefork but with hot-restart capability</li>
</ul>
devdata/https_mojolicious.io_blog_2017_12_01_day-1-getting-started view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/11/30/mojolicious-advent-2017/index.html" rel="prev"><strong>Previous Article</strong> Mojolicious Advent 2017</a></li>
<li class="next"><a href="/blog/2017/12/02/day-2-the-stash/index.html" rel="next"><strong>Next Article</strong> Day 2: The Stash </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_02_day-2-the-stash view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 2: The Stash</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-02">Dec 2, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="leather bag" src="/blog/2017/12/02/day-2-the-stash/bag-1854148_1920.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>In Mojolicious, when processing a request and preparing a response one of the most important concepts is "the stash".
Since it is a non-blocking framework, your code can't use global variables to store any state during processing.
If you did and some other code were to run, it could very easily get cross-talk between requests.</p>
<p>The stash is the place you can store information while you process it.
It is just a simple hash reference that is attached to the controller object that is processing the request.
It lives and dies with that one transaction.</p>
<p>While you can and should use it as a scratchpad, it really is much more.
The stash controls almost every aspect of the response that you generate.
Let's look a little closer to see how it works</p>
</section>
<section id="section-2">
<h2>Using the Stash for Rendering Text</h2>
<p>In the previous post, we discussed the most simple 'Hello world' application.</p>
<pre><code>use Mojolicious::Lite;
get '/' => {text => 'Hello ð World!'};
app->start;
</code></pre>
<p>While that is a very simple working case, a more common example would look like</p>
<pre><code>use Mojolicious::Lite;
get '/' => sub {
devdata/https_mojolicious.io_blog_2017_12_02_day-2-the-stash view on Meta::CPAN
Both of those, as well as the <code>template</code> will be rendered with the content type <code>text/html</code>.
To use something different, you can specify it with the <code>format</code> key.</p>
<pre><code>use Mojolicious::Lite;
get '/' => {text => 'hello ð world!', format => 'txt'};
app->start;
</code></pre>
<p>Where the understood formats are listed <a href="http://mojolicious.org/perldoc/Mojolicious/Types#DESCRIPTION">here</a> (and more <a href="http://mojolicious.org/perldoc/Mojolicious/Types#DESCRIPTION">can be added</a>).</p>
<p>The others all have meanings, some of which you can probably figure out on your own, but this post has gone on long enough.
Those others will have to wait for another day.</p>
</section>
<small><p><a href="https://pixabay.com/en/bag-classic-leather-messenger-bag-1854148/">Image</a> in the Public Domain.</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/hello-world/">hello world</a>,
devdata/https_mojolicious.io_blog_2017_12_02_day-2-the-stash view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/01/day-1-getting-started/index.html" rel="prev"><strong>Previous Article</strong> Day 1: Getting Started</a></li>
<li class="next"><a href="/blog/2017/12/03/day-3-using-named-routes/index.html" rel="next"><strong>Next Article</strong> Day 3: Using Named Routes </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_03_day-3-using-named-routes view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 3: Using Named Routes</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-03">Dec 3, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt=""my name is" stickers" src="/blog/2017/12/03/day-3-using-named-routes/my_name_is.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>One of the things we know from years of programming is that you should never hard-code anything if you don't have to.
And yet far too many web application hard-code their urls, especially internal ones.
But what if you didn't have to?</p>
<p>Each Mojolicious route has its own <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Routing#Named-routes">name</a> which can be used to generate urls.
If you don't specify one, one is generated, but you shouldn't rely on that name, give it one that is meaningful and relevant to your purposes.
In lite apps, the name is the last parameter, after any defaults or callbacks.
(In a full app it is an attribute, but we'll talk about those in another post).</p>
<p>Then when you need a url, rather than hard-coding it, use <a href="http://mojolicious.org/perldoc/Mojolicious/Controller#url_for"><code>url_for</code></a> or related functionality to generate a url by name, you can even pass placeholder values if ...
Let's see how it works!</p>
</section>
<section id="section-2">
<h2>The North Pole Homepage</h2>
<p>Santa started out with a simple webapp.
It just had a main page and a page for him and his employees.
devdata/https_mojolicious.io_blog_2017_12_03_day-3-using-named-routes view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/02/day-2-the-stash/index.html" rel="prev"><strong>Previous Article</strong> Day 2: The Stash</a></li>
<li class="next"><a href="/blog/2017/12/04/day-4-dont-fear-the-full-app/index.html" rel="next"><strong>Next Article</strong> Day 4: Don't Fear the Full App </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_04_day-4-dont-fear-the-full-app view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 4: Don't Fear the Full App</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-04">Dec 4, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Arucaria trees in Curitiba Brazil" src="/blog/2017/12/04/day-4-dont-fear-the-full-app/arucaria.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>One of the most common misconceptions about Mojolicious is that there is a large difference between the declarative "Lite" apps that we have seen so far and large-scale structured "Full" apps.
Nothing could be further from the truth.
<a href="http://mojolicious.org/perldoc/Mojolicious/Lite">Mojolicious::Lite</a> is a very tiny wrapper around the so-called "Full" app architecture, giving it the approachable keyword syntax.</p>
<p>Because it is much nicer to have concise single-file examples for documentation most of Mojolicious' documentation uses Lite syntax most of the time.
It is understandable that people worry about migrating (or as we call it "growing") even once their apps would benefit from Object-Oriented structure; after all the docs seem geared towards Lite apps.
However, let those fears go, the transition is easy.
And once you understand it, the documentatation examples are trivial to translate.</p>
<p>Plus, Mojolicious comes with two forms of help when transitioning.
The first is the <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Growing">Growing Guide</a> which covers everything this post will but from the perspective of porting an existing application (which I won't duplicate here).
The second is the <a href="http://mojolicious.org/perldoc/Mojolicious/Command/inflate">inflate command</a> which can even start you on the process by moving your templates from the data section and into their own files.</p>
<p>That said, in order to futher demystify things, I'm going to cover some of the differences and pull back the curtain on the Lite syntax itself.</p>
</section>
<section id="section-2">
<h2>Let Me Convince You</h2>
<p>After repeated attempts to convince people that there is very little difference between the two, I've found that there is one really great way to turn the conversation.
I show them the code.
devdata/https_mojolicious.io_blog_2017_12_04_day-4-dont-fear-the-full-app view on Meta::CPAN
The keywords <code>helper</code>, <code>hook</code>, and <code>plugin</code> are just methods on the app, so <code>plugin ...</code> becomes <code>$app->plugin(...)</code>, etc.</p>
<p>The routing methods</p>
<ul>
<li><code>any</code></li>
<li><code>del</code> (as <code>delete</code>)</li>
<li><code>get</code></li>
<li><code>options</code></li>
<li><code>patch</code></li>
<li><code>post</code></li>
<li><code>put</code></li>
<li><code>websocket</code></li>
</ul>
<p>are methods on route objects used exactly as they were before.
To get the toplevel route object, call <code>$app->routes</code>; by convention we call this toplevel route object <code>$r</code>.</p>
<pre><code>get '/' => sub { ... } => 'route_name';
</code></pre>
devdata/https_mojolicious.io_blog_2017_12_04_day-4-dont-fear-the-full-app view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/03/day-3-using-named-routes/index.html" rel="prev"><strong>Previous Article</strong> Day 3: Using Named Routes</a></li>
<li class="next"><a href="/blog/2017/12/05/day-5-your-apps-built-in-commands/index.html" rel="next"><strong>Next Article</strong> Day 5: Your App's Built-In Commands </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_05_day-5-your-apps-built-in-commands view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 5: Your App's Built-In Commands</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-05">Dec 5, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Space shuttle Atlantis liftoff" src="/blog/2017/12/05/day-5-your-apps-built-in-commands/1200px-Rocket_prolant.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>I mentioned at the outset of this series that Mojolicious applications are more than just web servers.
I then showed how you can start a web server using the <a href="http://mojolicious.org/perldoc/Mojolicious/Command/daemon"><code>daemon</code></a> or <a href="http://mojolicious.org/perldoc/Mojolicious/Command/prefork"><code>prefork</code></a> comman...
In the previous post, I mentioned an <a href="http://mojolicious.org/perldoc/Mojolicious/Command/inflate"><code>inflate</code></a> command that can help you with growing your app from Lite to Full.</p>
<p>But there are other commands, built right in to your app, that can help you be more productive right away!</p>
</section>
<section id="section-2">
<h2>Command Basics</h2>
<p>Before I start, I want to briefly discuss the <a href="http://mojolicious.org/perldoc/mojo"><code>mojo</code></a> application/script that comes bundled with the Mojolicious distribution.
This command is a tiny Mojolicious app (actually another "hello world") which can be thought of as the "null app".
The built-in commands work both for your application and this null one, so use whichever is more appropriate.
devdata/https_mojolicious.io_blog_2017_12_05_day-5-your-apps-built-in-commands view on Meta::CPAN
<pre><code>$ mojo generate lite_app myapp.pl
</code></pre>
<p>To create a <a href="http://mojolicious.org/perldoc/Mojolicious/Command/generate/app">Full app</a>, pass the name of the class</p>
<pre><code>$ mojo generate app MyApp
</code></pre>
<p>You can also create a <a href="http://mojolicious.org/perldoc/Mojolicious/Command/generate/plugin">plugin project</a> or <a href="http://mojolicious.org/perldoc/Mojolicious/Command/generate/makefile">generate a Makefile</a>.</p>
<p>There is some more to say on the subject of file generation, but since this is an overview post, I'll leave it at that for now.</p>
<h3>The version Command</h3>
<p>The <a href="http://mojolicious.org/perldoc/Mojolicious/Command/version"><code>version</code></a> command is a simple utility to check your Mojolicious installation.</p>
<p>It outputs your current version of Perl and Mojolicious along with any installed optional libraries.
For example, you'll want to install <a href="https://metacpan.org/pod/IO::Socket::SSL">IO::Socket::SSL</a> if you want to fetch or serve sites over HTTPS.
It then checks to see if there is an updated version of Mojolicious available.</p>
<h3>The routes Command</h3>
devdata/https_mojolicious.io_blog_2017_12_05_day-5-your-apps-built-in-commands view on Meta::CPAN
<p>For example, we can run it on Santa's application from <a href="/blog/2017/12/03/day-3-using-named-routes">day 3</a>.</p>
<pre><code>$ perl santa.pl routes
/toy/:toy_name GET "toy"
/meet/:name GET "staff"
/ GET "home"
</code></pre>
<p>This shows you the three routes that were defined.
It shows the paths for each route including their placeholders, that all three handle GET, and their route name.
Using this output is especially helpful when using named routes, as we learned in that post; all the information you need is right in that table!</p>
<p>We can go a little deeper and ask for verbose output by adding a flag</p>
<pre><code>$ perl santa.pl routes -v
/toy/:toy_name .... GET "toy" ^\/toy/([^/.]+)/?(?:\.([^/]+))?$
/meet/:name .... GET "staff" ^\/meet/([^/.]+)/?(?:\.([^/]+))?$
/ .... GET "home" ^/?(?:\.([^/]+))?$
</code></pre>
<p>This output includes all the same stuff as before but this time it also adds a few extra items.
Certain routes are more complex, and while all these were simple and so no flags are shown, if one were an <code>under</code> route or a <code>websocket</code> it would be noted where the <code>....</code> are.
Finally it includes a pattern that is what is actually matched by the router.
This can be helpful sometimes when debugging why certain requests match (or more likely don't match) a certain route.
Note that the router checks each route in order top to bottom, the first to match is what is used.</p>
<h3>The get Command</h3>
<p>Now we're getting to the fun stuff!</p>
<p>Mojolicious comes with a <a href="http://mojolicious.org/perldoc/Mojo/UserAgent">user agent</a> and lots of post-processing power, including <a href="http://mojolicious.org/perldoc/Mojo/DOM">HTML/XML</a> and <a href="http://mojolicious.org/perldoc...
This command exposes those features together on the command line, like a smart version of cURL or wget.</p>
<p>Output is written to STDOUT so that you can redirect the result to a file if you'd like.
Because of that, headers are omitted from the output unless you pass <code>-v</code>.</p>
<p>Let's see what it can do!
You can find the latest version of <code>IO::Socket::SSL</code> using the <a href="https://github.com/metacpan/metacpan-api/blob/master/docs/API-docs.md">Meta::CPAN JSON API</a>.
The response is parsed as JSON and only the <code>version</code> element is output.</p>
<pre><code>mojo get https://fastapi.metacpan.org/v1/module/IO::Socket::SSL /version
devdata/https_mojolicious.io_blog_2017_12_05_day-5-your-apps-built-in-commands view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/04/day-4-dont-fear-the-full-app/index.html" rel="prev"><strong>Previous Article</strong> Day 4: Don't Fear the Full App</a></li>
<li class="next"><a href="/blog/2017/12/06/day-6-adding-your-own-commands/index.html" rel="next"><strong>Next Article</strong> Day 6: Adding Your Own Commands </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_06_day-6-adding-your-own-commands view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 6: Adding Your Own Commands</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-06">Dec 6, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Space shuttle Atlantis prepared for liftoff (night)" src="/blog/2017/12/06/day-6-adding-your-own-commands/1280px-Brightly_lit_STS-135_on_launch_pad_39a.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Everyone has written those one-off administration or check scripts.
There are probably a few cluttering your project root or bin directory right now.
Those have a problem beyond just the clutter: duplication.</p>
<p>Programmers hate duplication because of skew.
If code gets improved in one place, it is unlikely to be improved in all places, unless there is only the one.
So that script you wrote a while back, the one with the database connection you hand-rolled, is that still correct?</p>
devdata/https_mojolicious.io_blog_2017_12_06_day-6-adding-your-own-commands view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/05/day-5-your-apps-built-in-commands/index.html" rel="prev"><strong>Previous Article</strong> Day 5: Your App's Built-In Commands</a></li>
<li class="next"><a href="/blog/2017/12/07/day-7-using-template-variants-for-a-beta-landing-page/index.html" rel="next"><strong>Next Article</strong> Day 7: Using Template Variants For a Beta Landing Page </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_07_day-7-using-template-variants-for-a-beta-landing-page view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 7: Using Template Variants For a Beta Landing Page</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-07">Dec 7, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Single yellow tulip in a field of red tulips" src="/blog/2017/12/07/day-7-using-template-variants-for-a-beta-landing-page/1280px-Single_yellow_tulip_in_a_field_of_red_tulips.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p><a href="http://cpantesters.org">CPAN Testers</a> is a pretty big project with a long,
storied history. At its heart is a data warehouse holding all the test reports
made by people installing CPAN modules. Around that exists an ecosystem of
tools and visualizations that use this data to provide useful insight into the
status of CPAN distributions.</p>
<p>For the <a href="http://github.com/cpan-testers/cpantesters-web">CPAN Testers webapp
project</a>, I needed a way to
devdata/https_mojolicious.io_blog_2017_12_07_day-7-using-template-variants-for-a-beta-landing-page view on Meta::CPAN
<p>This is the main CPAN Testers application.</p>
</code></pre>
<p>Template variants are a useful feature in some edge cases, and this isn't the
first time I've found a good use for them. I've also used them to provide a
different layout template in "development" mode to display a banner saying
"You're on the development site". Useful for folks who are undergoing user
acceptance testing. The best part is that if the desired variant for that
specific template is not found, Mojolicious falls back to the main template. I
built a mock JSON API application which made extensive use of this fallback
feature, but that's another blog post for another time.</p>
</section>
<small><p><a href="https://commons.wikimedia.org/w/index.php?curid=2147460">Image</a> by Photo by and (c)2007 <a href="//commons.wikimedia.org/wiki/User:Jina_Lee" title="User:Jina Lee">Jina Lee</a> - <span class="int-own-work" lang="en"...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/rendering/">rendering</a>,
<a href="/blog/tag/templates/">templates</a>
devdata/https_mojolicious.io_blog_2017_12_07_day-7-using-template-variants-for-a-beta-landing-page view on Meta::CPAN
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/06/day-6-adding-your-own-commands/index.html" rel="prev"><strong>Previous Article</strong> Day 6: Adding Your Own Commands</a></li>
<li class="next"><a href="/blog/2017/12/08/day-8-mocking-a-rest-api/index.html" rel="next"><strong>Next Article</strong> Day 8: Mocking a REST API </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_08_day-8-mocking-a-rest-api view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 8: Mocking a REST API</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-08">Dec 8, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Two crash test dummies" src="/blog/2017/12/08/day-8-mocking-a-rest-api/1280px-crash-test-dummies.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>One of my applications is a pure-JavaScript UI for a JSON API. This UI
is an entirely different project that communicates with a public API
using an OpenAPI specification.</p>
<p>Our public API is huge and complex: To set up the public API, I need
a database, sample data, and three other private API servers that
perform individual tasks as directed by the public API. Worse, I would
need to set up a lot of different test scenarios with different kinds of
devdata/https_mojolicious.io_blog_2017_12_08_day-8-mocking-a-rest-api view on Meta::CPAN
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/07/day-7-using-template-variants-for-a-beta-landing-page/index.html" rel="prev"><strong>Previous Article</strong> Day 7: Using Template Variants For a Beta Landing Page</a></li>
<li class="next"><a href="/blog/2017/12/09/day-9-the-best-way-to-test/index.html" rel="next"><strong>Next Article</strong> Day 9: The Best Way to Test </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 9: The Best Way to Test</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-09">Dec 9, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Woman using chemistry lab equipment" src="/blog/2017/12/09/day-9-the-best-way-to-test/1280px-CSIRO_ScienceImage_2798_Testing_in_the_Laboratory.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Ok so it is a bit of a click-bait headline.
But that doesn't mean I don't believe it.</p>
<p><a href="http://mojolicious.org/perldoc/Test/Mojo">Test::Mojo</a> is a test framework for websites and related technologies.
While its true that there are many such tools, this one gets its power comes from combining so many of the tools that Mojolicious provides.
A full non-blocking web server, including websockets, an <a href="http://mojolicious.org/perldoc/Mojo/IOLoop">event loop</a>, an <a href="http://mojolicious.org/perldoc/Mojo/DOM">XML/HTML DOM parser</a>, <a href="http://mojolicious.org/perldoc/Mojo/J...
Further, with the recent additions in support of <a href="http://mojolicious.org/perldoc/Mojo/Base#with_roles">roles</a> (which will be discussed in a future post), Test::Mojo is becoming an extensible testing platform.</p>
<p>In this article, I'll give a quick overview of how to use Test::Mojo and some of its methods.
Rest assured you'll see more of it as the series continues.</p>
</section>
<section id="section-2">
<h2>Getting Started</h2>
<p>The topmatter of a Test::Mojo script usually is fairly consistent.</p>
devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test view on Meta::CPAN
Of couse how you use your configuration might vary but if your app does something like</p>
<pre><code>has pg => sub {
my $app = shift;
return Mojo::Pg->new($app->config->{pg});
};
</code></pre>
<p>Then you could override whatever configuration might be present in your system by doing</p>
<pre><code>my $t = Test::Mojo->new('MyApp', {pg => 'postgresql://testuser:testpass@/testdb'});
</code></pre>
<p>If you use <a href="http://mojolicious.org/perldoc/Mojolicious/Plugin/Config">Mojolicious::Plugin::Config</a> or <a href="http://mojolicious.org/perldoc/Mojolicious/Plugin/JSONConfig">Mojolicious::Plugin::JSONConfig</a> or one of several other thi...
If you use some other loader on CPAN (that is Mojolicious aware) and it doesn't support this somewhat newish feature, please point it out to the author, it is easy to add.
Note that this does not work for Lite apps because it has inject the configuration overrides as the application is being built, something which isn't possible for a Lite app.</p>
<p>Finally you might find yourself in a situation where you already have an instantiated application.
If that is the case just pass it to the constructor.</p>
<pre><code>my $app = build_my_app();
devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test view on Meta::CPAN
<p>You can make requests with most of the same arguments as to <a href="http://mojolicious/perldoc/Mojo/UserAgent#METHODS">Mojo::UserAgent</a>.
These can include headers as a hash reference:</p>
<pre><code>$t->get_ok('/login', {'X-Application-Auth' => 'custom value'});
</code></pre>
<p>Requests with JSON, form, for multipart data are built via <a href="http://mojolicious.org/perldoc/Mojo/UserAgent/Transactor#GENERATORS">content generators</a>.
You can <a href="http://mojolicious.org/perldoc/Mojo/UserAgent/Transactor#add_generator">add your own</a> generator too; perhaps the subject of another article if there is interest.</p>
<pre><code>$t->post_ok('/login', form => {user => 'me', pass => 'secr3t'});
$t->put_ok('/inventory/12345', json => {type => 'widget', value => 'tons'});
</code></pre>
<p>Or you can submit raw data as a trailing argument</p>
<pre><code>use Mojo::XMLRPC 'encode_xmlrpc'; # from CPAN
$t->post_ok('/xmlrpc', encode_xmlrpc(call => 'mymethod', 'myarg'));
</code></pre>
<p>There are methods for all the standard HTTP methods.
The result of these tests is essentially the succes of the transport.</p>
<p>You'll also likely want to check the return status.</p>
<pre><code>$t->get_ok('/')->status_is(200);
</code></pre>
devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test view on Meta::CPAN
<pre><code>$t->get_ok('/santa_list/joel.json')
->json_is('/status', 'nice');
</code></pre>
<p>Of course there are methods to test HTML responses.
Since it makes little sense to test the whole thing (and if you wanted to you could use <code>content_</code>), these take a <a href="http://mojolicious.org/perldoc/Mojo/DOM/CSS">CSS3 Selector</a> to narrow their focus in a similar manner to the JSON...
To inspect the textual portions of the HTML response, use the <code>text_</code> methods with a selector.
For other tests, there might not be text to test, or the value doesn't matter.
For those cases there are <code>element_exists</code>, <code>element_exists_not</code>, and <code>element_count_is</code>, which, as their names indicate, take a selector and tries to find if or how many elements match it.
These really need a post of their own, but as a few examples</p>
<pre><code>$t->text_is('div.main-content p:nth-of-type(2)', 'This is the third paragraph of the main-section of text');
$t->element_exists('img[src="kitten.jpg"]');
</code></pre>
<h2>Testing Websockets</h2>
<p>Websockets are an intersting challenge to test, however Test::Mojo makes them easy.
We've already seen that you open a websocket with <code>websocket_ok</code>.</p>
devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/08/day-8-mocking-a-rest-api/index.html" rel="prev"><strong>Previous Article</strong> Day 8: Mocking a REST API</a></li>
<li class="next"><a href="/blog/2017/12/10/day-10-give-the-customer-what-they-want/index.html" rel="next"><strong>Next Article</strong> Day 10: Give the Customer What They Want </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_10_day-10-give-the-customer-what-they-want view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 10: Give the Customer What They Want</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-10">Dec 10, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Wood bar counter with chairs" src="/blog/2017/12/10/day-10-give-the-customer-what-they-want/cafe-wood-vintage-retro-seat-restaurant-946984-pxhere.com.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Writing an API can be as easy as taking the results of some database query and presenting it to the user.
A more advanced one can often present the data in one of multiple formats.
The user can then specify which format they want.</p>
<p>JSON is currently the most popular format for new APIs.
XML is another common one and was certainly king before JSON hit the scene.
An API might choose to make an HTML format of the data available, whether in some representation of the data or to render documentation about the API itself.
Of course there are many others.</p>
devdata/https_mojolicious.io_blog_2017_12_10_day-10-give-the-customer-what-they-want view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/09/day-9-the-best-way-to-test/index.html" rel="prev"><strong>Previous Article</strong> Day 9: The Best Way to Test</a></li>
<li class="next"><a href="/blog/2017/12/11/day-11-useragent-content-generators/index.html" rel="next"><strong>Next Article</strong> Day 11: UserAgent Content Generators </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_11_day-11-useragent-content-generators view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 11: UserAgent Content Generators</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-11">Dec 11, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Artist painting" src="/blog/2017/12/11/day-11-useragent-content-generators/artist-painting-1459778857j86.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>We have already seen <a href="http://mojolicious.org/perldoc/Mojo/UserAgent">Mojo::UserAgent</a> used to make HTTP requests in this series.
In fact we've already seen how you can use <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Cookbook#USER-AGENT">Content Generators</a> to build requests <a href="/blog/2017/12/09/day-9-the-best-way-to-test#making-requests">in tests</a>...
But we didn't look at how they work or how you can add new ones.</p>
</section>
<section id="section-2">
<h2>Using Content Generators</h2>
<p>The UserAgent, and more specifically its <a href="http://mojolicious.org/perl/Mojo/UserAgent/Transactor">Transactor</a>, help you by making it easy to create HTTP requests.
Consider the most basic request with a body, a <code>POST</code> with a binary body, maybe ASCII text.
In that case, the request</p>
<pre><code>my $ua = Mojo::UserAgent->new;
$ua->post(
'/url',
{'Content-Type' => 'text/plain'},
'some binary content'
);
</code></pre>
<p>is equivalent to</p>
<pre><code>my $ua = Mojo::UserAgent->new;
my $tx = $ua->build_tx(POST => '/url');
$tx->req->headers->header('Content-Type', 'text/plain');
$tx->req->body('some binary content');
$ua->start($tx);
</code></pre>
<p>A Content Generators is a shortcut to help build requests for certain types of content.
The previous example wasn't technically a Content Generator as these are indicated by a generator name and usually accept arguments.
That said, you can almost imagine that setting the body content is the default generator.</p>
<p>The simplest use of an actual Content Generator is the one the builds a JSON request.
A JSON post like</p>
<pre><code>$ua->post('/url', json => {some => ['json', 'data']});
</code></pre>
<p>does two things, it builds the binary form of the body and it sets the <code>Content-Type</code> header.
To do it manually it would be either</p>
<pre><code>use Mojo::JSON 'encode_json';
$ua->post(
'/url',
{'Content-Type' => 'application/json'},
encode_json({some => ['json', 'data']})
);
</code></pre>
<p>or a similar example to the above using <code>build_tx</code>.
I think you'll agree that the generator form is much easier to read and "does what you mean".</p>
<p>At the time of this writing, Mojo::UserAgent comes with three <a href="http://mojolicious.org/perldoc/Mojo/UserAgent/Transactor#tx">built-in Content Generators</a>, including the <code>json</code> one as we've already seen.</p>
devdata/https_mojolicious.io_blog_2017_12_11_day-11-useragent-content-generators view on Meta::CPAN
<pre><code class="hljs"><span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::Base</span> -strict;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::UserAgent</span>;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::JSON</span> '<span class="hljs-string">encode_json</span>';
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::File</span>;
<span class="hljs-keyword">my</span> <span class="hljs-type">$url</span> = '<span class="hljs-string">https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart</span>';
<span class="hljs-keyword">my</span> <span class="hljs-type">$token</span> = '<span class="hljs-string">XXXXXXXXXX</span>';
<span class="hljs-keyword">my</span> <span class="hljs-type">$file</span> = <span class="hljs-function">Mojo::File</span>->new('<span class="hljs-string">local/path/to/image.jpg</span>');
<span class="hljs-keyword">my</span> <span class="hljs-type">$ua</span> = <span class="hljs-function">Mojo::UserAgent</span>->new;
<span class="hljs-type">$ua</span>-><span class="hljs-type">post</span>(
<span class="hljs-type">$url</span>,
{
Authorization => "<span class="hljs-string">Bearer </span><span class="hljs-type">$token</span>",
'<span class="hljs-string">Content-Type</span>' => '<span class="hljs-string">multipart/related</span>',
},
multipart => [
{
'<span class="hljs-string">Content-Type</span>' => '<span class="hljs-string">application/json; charset=UTF-8</span>',
content => encode_json({name => '<span class="hljs-string">myObject</span>'}),
},
devdata/https_mojolicious.io_blog_2017_12_11_day-11-useragent-content-generators view on Meta::CPAN
<p>By the time I finished I had completely rewritten the module and decided that perhaps others would benefit from it in environments already using the Mojo stack.
So with much thanks to XMLRPC::Fast and its author Sébastien Aperghis-Tramoni I released my own as <a href="https://metacpan.org/pod/Mojo::XMLRPC">Mojo::XMLRPC</a>.
My module (as did the original) only has functions that build the XML payloads.
Therefore, to make a simple request, pass the result of encoding as XML-RPC as the body of a request, like so</p>
<pre><code class="hljs"><span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::Base</span> -strict;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::UserAgent</span>;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::XMLRPC</span> qw[encode_xmlrpc decode_xmlrpc];
<span class="hljs-keyword">my</span> <span class="hljs-type">$ua</span> = <span class="hljs-function">Mojo::UserAgent</span>->new;
<span class="hljs-keyword">my</span> <span class="hljs-type">$tx</span> = <span class="hljs-type">$ua</span>-><span class="hljs-type">post</span>(
'<span class="hljs-string">/rpc</span>',
{'<span class="hljs-string">Content-Type</span>' => '<span class="hljs-string">text/xml</span>'},
encode_xmlrpc(call => '<span class="hljs-string">target_method</span>', '<span class="hljs-string">arg1</span>', '<span class="hljs-string">arg2</span>')
);
<span class="hljs-keyword">my</span> <span class="hljs-type">$res</span> = decode_xmlrpc(<span class="hljs-type">$tx</span>-><span class="hljs-type">res</span>-><span class="hljs-type">body</span>);
</code></pre>
<p>which produces a request like</p>
devdata/https_mojolicious.io_blog_2017_12_11_day-11-useragent-content-generators view on Meta::CPAN
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::UserAgent</span>;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::XMLRPC</span> qw[encode_xmlrpc decode_xmlrpc];
<span class="hljs-keyword">my</span> <span class="hljs-type">$ua</span> = <span class="hljs-function">Mojo::UserAgent</span>->new;
<span class="hljs-type">$ua</span>-><span class="hljs-type">transactor</span>-><span class="hljs-type">add_generator</span>(xmlrpc => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> (<span class="hljs-type">$transactor</span>, <span class="hljs-type">$tx</span>, <span class="hljs-type">@args</span>) = <span class="hljs-type">@_</span>;
<span class="hljs-type">$tx</span>-><span class="hljs-type">req</span>-><span class="hljs-type">headers</span>-><span class="hljs-type">content_type</span>('<span class="hljs-string">text/xml</span>');
<span class="hljs-type">$tx</span>-><span class="hljs-type">req</span>-><span class="hljs-type">body</span>(encode_xmlrpc(call => <span class="hljs-type">@args</span>));
});
<span class="hljs-keyword">my</span> <span class="hljs-type">$tx</span> = <span class="hljs-type">$ua</span>-><span class="hljs-type">post</span>('<span class="hljs-string">/rpc</span>', xmlrpc => '<span class="hljs-string">target_m...
<span class="hljs-keyword">my</span> <span class="hljs-type">$res</span> = decode_xmlrpc(<span class="hljs-type">$tx</span>-><span class="hljs-type">res</span>-><span class="hljs-type">body</span>);
</code></pre>
<p>which produces an output essentially identical to the first.</p>
<p>At first glance it only appears to be a modest improvement.
However, once defined, it does cut down on repeated code for subsequent requests.
Thus the benefit grows the more times it is used.
devdata/https_mojolicious.io_blog_2017_12_11_day-11-useragent-content-generators view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/10/day-10-give-the-customer-what-they-want/index.html" rel="prev"><strong>Previous Article</strong> Day 10: Give the Customer What They Want</a></li>
<li class="next"><a href="/blog/2017/12/12/day-12-more-than-a-base-class/index.html" rel="next"><strong>Next Article</strong> Day 12: More Than a Base Class </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_12_day-12-more-than-a-base-class view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 12: More Than a Base Class</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-12">Dec 12, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Golden Gate Bridge viewed and Fort Point" src="/blog/2017/12/12/day-12-more-than-a-base-class/1280px-GG-ftpoint-bridge-2.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Through this series, you've seen the module <a href="http://mojolicious.org/perldoc/Mojo/Base">Mojo::Base</a> referenced several times, though briefly and mostly in passing.
It shouldn't be taken lightly however, it packs a lot of punch in one import statement!
Nearly every file in the Mojolicious distribution uses it, either directly or indirectly.
So what is it?</p>
<p>First it imports several handy pragma that make your code safer and some features that are useful.
Second, it can be a base class to the current package, or establish a parent class, or even define a role.
Let's see how it does it.</p>
devdata/https_mojolicious.io_blog_2017_12_12_day-12-more-than-a-base-class view on Meta::CPAN
->max_redirects(10)
->get('http://mojolicious.org')
->res
->dom
->at('title')
->text;
</code></pre>
<p>Frequent users of such Javascript libraries as <a href="https://jquery.com/">jQuery</a> or <a href="https://lodash.com/">lodash</a> will find this type of chaining very familiar.
Once you get the hang of this style it is <a href="https://metacpan.org/pod/MooX::ChainedAttributes">hard to let go of it</a>.
In a future post I intent to discuss several of the fluent interfaces that the Mojo stack provides.</p>
<h3>The tap Method</h3>
<p>Speaking of fluent interfaces, Mojo::Base provides an interesting method called <code>tap</code>, which is (in comp-sci terms) a <a href="https://en.wikipedia.org/wiki/SKI_combinator_calculus">K-combinator</a>.
This is a more advanced feature, but it allows you to insert a non-chainable call into a method chain without breaking it.
The first argument is the method or callback to be called, any additional arguments are passed to the tapped subroutine.
Within that subroutine the invocant is available as the first argument (before any passed arguments) or as <code>$_</code>.</p>
<p>If you had a proxy that you needed to setup before running the previous example, you could do</p>
devdata/https_mojolicious.io_blog_2017_12_12_day-12-more-than-a-base-class view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/11/day-11-useragent-content-generators/index.html" rel="prev"><strong>Previous Article</strong> Day 11: UserAgent Content Generators</a></li>
<li class="next"><a href="/blog/2017/12/13/day-13-more-about-roles/index.html" rel="next"><strong>Next Article</strong> Day 13: More About Roles </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_13_day-13-more-about-roles view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 13: More About Roles</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-13">Dec 13, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Pile of hats" src="/blog/2017/12/13/day-13-more-about-roles/amsterdam_hats.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Before we get ahead of ourselves, what are roles?
Briefly stated, roles enable composing functionality (usually methods) into a class without without implying a change of inheritence.
Said another way, roles let you specify what a class does without changing what it is.
For a better description, check out Toby Inkster's article <a href="http://radar.oreilly.com/2014/01/horizontal-reuse-an-alternative-to-inheritance.html">Horizontal Reuse: An Alternative to Inheritance</a>.</p>
<p>An important utility of roles is that you can easily use more than one role at the same time in the same consuming class.
With inheritance, especially of third-party functionality, you have to choose one set of extensions to utilize.
This is because the author of the subclass establishes the inheritance.
devdata/https_mojolicious.io_blog_2017_12_13_day-13-more-about-roles view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/12/day-12-more-than-a-base-class/index.html" rel="prev"><strong>Previous Article</strong> Day 12: More Than a Base Class</a></li>
<li class="next"><a href="/blog/2017/12/14/day-14-you-promised-to-call/index.html" rel="next"><strong>Next Article</strong> Day 14: You Promised To Call! </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_14_day-14-you-promised-to-call view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 14: You Promised To Call!</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-14">Dec 14, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Two hands with interlocked pinkies, a pinky swear" src="/blog/2017/12/14/day-14-you-promised-to-call/pinky_swear.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>A new feature of <a href="http://mojolicious.org/">Mojolicious</a>, as of <a href="https://metacpan.org/release/SRI/Mojolicious-7.49">7.49</a>, is the implementation of the <a href="https://promisesaplus.com/implementations#in-ot...
</section>
<section id="section-2">
<h2>Background</h2>
<p>"Normal" Perl code runs synchronously: it does each step it is told to, one at a time, and only that. This is also known as "blocking", since the program cannot do anything else.</p>
<p>The essence of a non-blocking code framework is that if you are waiting for something, you can register with the framework what to do when that thing happens. It can then do other processing tasks in the meantime. This means you don't have lot...
<p>Originally this was done just using callbacks, but this lead to what is known as "callback hell": each callback contains the next callback, at an increasing level of indentation. Even harder to keep track of is if the functions are kept ...
devdata/https_mojolicious.io_blog_2017_12_14_day-14-you-promised-to-call view on Meta::CPAN
<img alt="author image" src="https://secure.gravatar.com/avatar/c6e74e4e0ab61c61db655f0e60c9f8a6.jpg">
</div>
<div class="about">
<h5>Ed J</h5>
<p>Ed J (aka "mohawk" on IRC) has been using Perl for a long time. He is currently porting the reference <a href="http://graphql.org/">GraphQL</a> implementation from the <a href="http://graphql.org/graphql-js/">Java...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/13/day-13-more-about-roles/index.html" rel="prev"><strong>Previous Article</strong> Day 13: More About Roles</a></li>
<li class="next"><a href="/blog/2017/12/15/day-15-start-a-new-yancy-app/index.html" rel="next"><strong>Next Article</strong> Day 15: Start a New Yancy App </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_15_day-15-start-a-new-yancy-app view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 15: Start a New Yancy App</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-15">Dec 15, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Workers on a scaffold" src="/blog/2017/12/15/day-15-start-a-new-yancy-app/scaffold.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p><a href="http://metacpan.org/pod/Yancy">Yancy</a> is a new content management
plugin for the <a href="http://mojolicious.org">Mojolicious web framework</a>.
Yancy allows you to easily administrate your siteâÂÂs content just by
describing it using <a href="http://json-schema.org">JSON Schema</a>. Yancy
supports <a href="http://metacpan.org/pod/Yancy::Backend">multiple backends</a>, so
your site's content can be in
<a href="http://metacpan.org/pod/Yancy::Backend::Pg">Postgres</a>,
<a href="http://metacpan.org/pod/Yancy::Backend::Mysql">MySQL</a>, and
<a href="http://metacpan.org/pod/Yancy::Backend::Dbic">DBIx::Class</a>.</p>
</section>
<section id="section-2">
<h2>Demonstration</h2>
<p>For an demonstration application, letâÂÂs create a simple blog using
<a href="http://mojolicious.org/perldoc/Mojolicious/Lite">Mojolicious::Lite</a>.
First we need to create a database schema for our blog posts. Let's use
<a href="http://metacpan.org/pod/Mojo::Pg">Mojo::Pg</a> and its <a href="http://metacpan.org/pod/Mojo::Pg::Migrations">migrations
feature</a> to create a table
called "blog" with fields for an ID, a title, a date, some markdown, and
some HTML.</p>
<pre><code class="hljs"><span class="hljs-comment"># myapp.pl</span><span class="hljs-comment">
</span><span class="hljs-keyword">use</span> <span class="hljs-function">Mojolicious::Lite</span>;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::Pg</span>;
<span class="hljs-keyword">my</span> <span class="hljs-type">$pg</span> = <span class="hljs-function">Mojo::Pg</span>->new( '<span class="hljs-string">postgres://localhost/blog</span>' );
<span class="hljs-type">$pg</span>-><span class="hljs-type">migrations</span>-><span class="hljs-type">from_data</span>-><span class="hljs-type">migrate</span>;
<span class="hljs-keyword">__DATA__</span>
@@ migrations
-- 1 up
CREATE TABLE blog (
id SERIAL PRIMARY KEY,
title VARCHAR NOT NULL,
created TIMESTAMP NOT NULL DEFAULT NOW(),
markdown TEXT NOT NULL,
devdata/https_mojolicious.io_blog_2017_12_15_day-15-start-a-new-yancy-app view on Meta::CPAN
<p>Now we can start up our app and go to <a href="http://127.0.0.1:3000/yancy">http://127.0.0.1:3000/yancy</a> to
manage our site's content:</p>
<pre><code>$ perl myapp.pl daemon
Server available at http://127.0.0.1:3000
</code></pre>
<p><img alt="Screen shot of adding a new blog item with Yancy" src="adding-item.png">
<img alt="Screen shot of Yancy after the new blog item is added" src="item-added.png"></p>
<p>Finally, we need some way to display our blog posts. <a href="http://metacpan.org/pod/Mojolicious::Plugin::Yancy#HELPERS">Yancy provides
helpers to access our
data</a>. Let's
use the <code>list</code> helper to display a list of blog posts. This helper takes
a collection name and gives us a list of items in that collection. It
also allows us to search for items and order them to our liking. Since
we've got a blog, we will order by the creation date, descending.</p>
<pre><code class="hljs">get '<span class="hljs-string">/</span>' => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> ( <span class="hljs-type">$c</span> ) = <span class="hljs-type">@_</span>;
<span class="hljs-keyword">return</span> <span class="hljs-type">$c</span>-><span class="hljs-type">render</span>(
'<span class="hljs-string">index</span>',
posts => [ <span class="hljs-type">$c</span>-><span class="hljs-type">yancy</span>-><span class="hljs-type">list</span>(
'<span class="hljs-string">blog</span>', {}, { order_by => { -desc => '<span class="hljs-string">created</span>' } },
) ],
);
};
</code></pre>
<p>Now we just need an HTML template to go with our route! Here, I use the standard
<a href="http://getbootstrap.com/docs/4.0/getting-started/introduction/#starter-template">Bootstrap 4 starter template</a>
and add this short loop to render our blog posts:</p>
<pre><code><main role="main" class="container">
% for my $post ( @{ stash 'posts' } ) {
<%== $post->{html} %>
% }
</main>
</code></pre>
<p><a href="04-template.pl">Now we have our completed application</a> and we can test
to see our blog post:</p>
<pre><code>$ perl myapp.pl daemon
Server available at http://127.0.0.1:3000
</code></pre>
<p><img alt="The rendered blog post with our template" src="blog-post.png"></p>
<p>Yancy provides a rapid way to get started building a Mojolicious
application (above MojoliciousâÂÂs already rapid development). Yancy
provides a basic level of content management so site developers can
focus on what makes their site unique.</p>
</section>
<small><p><a href="http://www.publicdomainpictures.net/view-image.php?image=6416">Image</a> in the public domain.</p>
</small>
devdata/https_mojolicious.io_blog_2017_12_15_day-15-start-a-new-yancy-app view on Meta::CPAN
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/14/day-14-you-promised-to-call/index.html" rel="prev"><strong>Previous Article</strong> Day 14: You Promised To Call!</a></li>
<li class="next"><a href="/blog/2017/12/16/day-16-the-secret-life-of-sessions/index.html" rel="next"><strong>Next Article</strong> Day 16: The Secret Life of Sessions </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_16_day-16-the-secret-life-of-sessions view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 16: The Secret Life of Sessions</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-16">Dec 16, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Pile of Scrabble tiles" src="/blog/2017/12/16/day-16-the-secret-life-of-sessions/scrabble.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>As you all know, HTTP is a stateless protocol.
In Mojolicious applications the session is used to maintain state between requests.
These sessions are managed by the application's <a href="http://mojolicious.org/perldoc/Mojolicious/#sessions">session manager</a>.</p>
<p>During each request, the <a href="http://mojolicious.org/perldoc/Mojolicious/Controller#session">session</a> is just another hash reference attached to the controller, in some ways like the <a href="/blog/2017/12/02/day-2-the-stash">stash</a>, exc...
Mojolicious does this by encoding the structure, first as JSON then Base64.
It then signs the resulting string using HMAC-SHA1 and the application's <a href="http://mojolicious.org/perldoc/Mojolicious#secrets">secret</a> to prevent tampering and stores it as a cookie on the response to the client.</p>
devdata/https_mojolicious.io_blog_2017_12_16_day-16-the-secret-life-of-sessions view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/15/day-15-start-a-new-yancy-app/index.html" rel="prev"><strong>Previous Article</strong> Day 15: Start a New Yancy App</a></li>
<li class="next"><a href="/blog/2017/12/17/day-17-the-wishlist-app/index.html" rel="next"><strong>Next Article</strong> Day 17: The Wishlist App </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_17_day-17-the-wishlist-app view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 17: The Wishlist App</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-17">Dec 17, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Living room, Christmas tree, and presents" src="/blog/2017/12/17/day-17-the-wishlist-app/xmas_tree.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>For today's article, I really wanted to demonstrate concepts using a practical example appliation.
It is possible I let the exaxmple get away from me!</p>
<p>In today's article I indend to show how to use template composition techniques to produce a wishlist app.
We will cover <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Rendering#Layouts">layouts</a>, <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Rendering#Partial-templates">partial templates</a>, <a href="http://mojolicious.org/pe...
<p>The data model is admittedly rough, however I think my plan will be to make that a feature and not a bug.
Today we will example concepts mostly relating to the templates, then in tomorrows post I will migrate the model from using the simplistic persistence of <a href="https://metacpan.org/pod/DBM::Deep">DBM::Deep</a> that it uses now to <a href="https://...
</section>
<section id="section-2">
<p>At that point I hope to put the application into a repository of its own.
In the meantime however, you can see the application in the source for this <a href="https://github.com/MojoliciousDotIO/mojolicious.io/tree/master/blog/2017/12/17/day-17-the-wishlist-app/wishlist">article</a>.
To run it, you will need to install two additional modules, DBM::Deep and <a href="https://metacpan.org/pod/LinkEmbedder">LinkEmbedder</a>.</p>
<pre><code>$ cpanm Mojolicious DBM::Deep LinkEmbedder
</code></pre>
devdata/https_mojolicious.io_blog_2017_12_17_day-17-the-wishlist-app view on Meta::CPAN
};
get '<span class="hljs-string">/list/:name</span>' => '<span class="hljs-string">list</span>';
get '<span class="hljs-string">/add</span>' => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> <span class="hljs-type">$c</span> = <span class="hljs-function">shift</span>;
<span class="hljs-keyword">my</span> <span class="hljs-type">$link</span> = <span class="hljs-type">$c</span>-><span class="hljs-type">link</span>(<span class="hljs-type">$c</span>-><span class="hljs-type">param</span>('<span class="hljs-...
<span class="hljs-type">$c</span>-><span class="hljs-type">render</span>('<span class="hljs-string">add</span>', <span class="hljs-function">link</span> => <span class="hljs-type">$link</span>);
};
post '<span class="hljs-string">/add</span>' => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> <span class="hljs-type">$c</span> = <span class="hljs-function">shift</span>;
<span class="hljs-keyword">my</span> <span class="hljs-type">$title</span> = <span class="hljs-type">$c</span>-><span class="hljs-type">param</span>('<span class="hljs-string">title</span>');
<span class="hljs-type">$c</span>-><span class="hljs-type">user</span>->{items}{<span class="hljs-type">$title</span>} = {
title => <span class="hljs-type">$title</span>,
url => <span class="hljs-type">$c</span>-><span class="hljs-type">param</span>('<span class="hljs-string">url</span>'),
purchased => 0,
};
<span class="hljs-type">$c</span>-><span class="hljs-type">redirect_to</span>('<span class="hljs-string">/</span>');
};
post '<span class="hljs-string">/update</span>' => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> <span class="hljs-type">$c</span> = <span class="hljs-function">shift</span>;
<span class="hljs-keyword">my</span> <span class="hljs-type">$user</span> = <span class="hljs-type">$c</span>-><span class="hljs-type">user</span>(<span class="hljs-type">$c</span>-><span class="hljs-type">param</span>('<span class="hljs-...
<span class="hljs-keyword">my</span> <span class="hljs-type">$item</span> = <span class="hljs-type">$user</span>->{items}{<span class="hljs-type">$c</span>-><span class="hljs-type">param</span>('<span class="hljs-string">title</span>'...
<span class="hljs-type">$item</span>->{purchased} = <span class="hljs-type">$c</span>-><span class="hljs-type">param</span>('<span class="hljs-string">purchased</span>');
<span class="hljs-type">$c</span>-><span class="hljs-type">redirect_to</span>('<span class="hljs-string">list</span>', name => <span class="hljs-type">$user</span>->{name});
};
post '<span class="hljs-string">/remove</span>' => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> <span class="hljs-type">$c</span> = <span class="hljs-function">shift</span>;
<span class="hljs-function">delete</span> <span class="hljs-type">$c</span>-><span class="hljs-type">user</span>->{items}{<span class="hljs-type">$c</span>-><span class="hljs-type">param</span>('<span class="hljs-string">title</span>&#...
<span class="hljs-type">$c</span>-><span class="hljs-type">redirect_to</span>('<span class="hljs-string">/</span>');
};
post '<span class="hljs-string">/login</span>' => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> <span class="hljs-type">$c</span> = <span class="hljs-function">shift</span>;
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">my</span> <span class="hljs-type">$name</span> = <span class="hljs-type">$c</span>-><span class="hljs-type">param</span>('<span class="hljs-string">name</span>')) {
<span class="hljs-type">$c</span>-><span class="hljs-type">session</span>->{name} = <span class="hljs-type">$name</span>;
}
<span class="hljs-type">$c</span>-><span class="hljs-type">redirect_to</span>('<span class="hljs-string">/</span>');
};
any '<span class="hljs-string">/logout</span>' => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> <span class="hljs-type">$c</span> = <span class="hljs-function">shift</span>;
<span class="hljs-type">$c</span>-><span class="hljs-type">session</span>(expires => <span class="hljs-number">1</span>);
devdata/https_mojolicious.io_blog_2017_12_17_day-17-the-wishlist-app view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/16/day-16-the-secret-life-of-sessions/index.html" rel="prev"><strong>Previous Article</strong> Day 16: The Secret Life of Sessions</a></li>
<li class="next"><a href="/blog/2017/12/18/day-18-the-wishlist-model/index.html" rel="next"><strong>Next Article</strong> Day 18: The Wishlist Model </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 18: The Wishlist Model</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-18">Dec 18, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Still Life: Vase with Pink Roses by Vincent van Gogh" src="/blog/2017/12/18/day-18-the-wishlist-model/van_gogh_still_life.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p><a href="https://mojolicious.io/blog/2017/12/17/day-17-the-wishlist-app/">Yesterday</a> we discussed templates features like layouts, partial templates, and content buffers.
We motivated the discussion by introducing a fully functioning example application that tracked user's Christmas wishlists.
That application did lack sophistication in the area of data storage, using <a href="https://metacpan.org/pod/DBM::Deep">DBM::Deep</a> for quickly getting a basic persistence layer.
While that worked well enough to demonstrate template functionality it was no triumph of the model layer.
Indeed some very hack techniques are used, especially in manipulating wishlist items, since there was no unique record ids.</p>
<p>Well as promised I have created a <a href="https://github.com/jberger/Wishlist">repository</a> for the application on Github.
I have also added several tags.
While development on the application may continue, those tags will remain for future readers.</p>
<p>The initial form of the application (as seen in yesterday's post) is tagged <a href="https://github.com/jberger/Wishlist/tree/blog_post/dbm_deep"><code>blog_post/dbm_deep</code></a>.
You are then invited to step through the commits <a href="https://github.com/jberger/Wishlist/compare/blog_post/dbm_deep...blog_post/full_app">from that one to <code>blog_post/full_app</code></a> to follow along as I port it from a Lite to a Full app...
<p>This article will briefly discuss the application as it exists in the next tag, <a href="https://github.com/jberger/Wishlist/tree/blog_post/sqlite_model"><code>blog_post/sqlite_model</code></a>.
At this point I have replaced DBM::Deep with <a href="https://metacpan.org/pod/Mojo::SQLite">Mojo::SQLite</a>, written a rudimentary model layer for it, and connected the two with the application via helpers.
Let's see how that improves the application and in the meantime, get a look at idiomatic database access in Mojolicious!</p>
</section>
<section id="section-2">
<h2>Model View Controller</h2>
<p>Most modern web applications adhere to a pattern called <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">Model View Controller</a> or MVC.
Much has been written about MVC, more than could be conveyed here.
Quickly though, the view is how data is displayed, the template.
devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model view on Meta::CPAN
However this isn't a model as such, a model really needs to have defined data layout (schema) and manipulation.</p>
<p>Many Perl users turn to <a href="https://metacpan.org/pod/DBIx::Class">DBIx::Class</a>, an <a href="https://en.wikipedia.org/wiki/Object-relational_mapping">Object-Relational Mapper</a> (ORM), and this is a great choice.
It hides most of the SQL and creates classes for the tables.
However some developers like staying a little closer to the SQL.</p>
<h2>Mojo-Flavored DBI</h2>
<p>The Mojolicious community has several modules that live partway between DBI and DBIx::Class.
I lovingly call them "Mojo-Flavored DBI" collectively.
The first of these was <a href="https://metacpan.org/pod/Mojo::Pg">Mojo::Pg</a> for <a href="https://www.postgresql.org/">PostgreSQL</a>.
Quickly, copycat modules were made, <a href="https://metacpan.org/pod/Mojo::mysql">Mojo::mysql</a> for <a href="https://www.mysql.com/">MySQL</a> and <a href="https://metacpan.org/pod/Mojo::SQLite">Mojo::SQLite</a> for the embedded database <a href="...
<p>These are attractive because they are lightweight in comparison to ORMs.
They feature schema migration management and similar <a href="https://mojolicious.io/blog/2017/12/12/day-12-more-than-a-base-class/">fluent interfaces</a> as Mojolicious.
They handle connection pooling and nonblocking access (emulated in the case of SQLite).
In recent versions, they also wrap <a href="https://metacpan.org/pod/SQL::Abstract">SQL::Abstract</a> which can be used to simplify certain common actions.
SQL::Abstract is also used by DBIx::Class, so as you'd expect, these have a feel similar to an ORM.</p>
<p>Going forward with this article, I will use Mojo::SQLite since it doesn't require an external database.</p>
devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model view on Meta::CPAN
<p>Here you can see how to move from the empty version 0 up to version 1.
You can also define how to move back down though it is ok to ignore those and not support downgrading.</p>
<p>The schema we define mimics the one we used yesterday.
Users have names.
Items have titles, urls, purchased state (SQLite doesn't have a boolean) and a reference to the user that requested it.</p>
<h2>The Model Class</h2>
<p>I extracted the business logic from the <a href="https://metacpan.org/pod/SQL::Abstract">original application's controller actions</a>, anything that handled persistence, and moved them to a dedicated class, <a href="https://github.com/jberger...
<pre><code class="hljs"><span class="hljs-keyword">package</span> <span class="hljs-function">Wishlist::Model</span>;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::Base</span> -base;
<span class="hljs-keyword">use</span> Carp ();
has sqlite => <span class="hljs-keyword">sub </span>{ <span class="hljs-function">Carp::croak</span> '<span class="hljs-string">sqlite is required</span>' };
<span class="hljs-keyword">sub </span><span class="hljs-function">add_user</span> {
<span class="hljs-keyword">my</span> (<span class="hljs-type">$self</span>, <span class="hljs-type">$name</span>) = <span class="hljs-type">@_</span>;
devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model view on Meta::CPAN
<span class="hljs-keyword">my</span> <span class="hljs-type">$r</span> = <span class="hljs-type">$app</span>-><span class="hljs-type">routes</span>;
<span class="hljs-type">$r</span>-><span class="hljs-type">get</span>('<span class="hljs-string">/</span>' => <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> <span class="hljs-type">$c</span> = <span class="hljs-function">shift</span>;
<span class="hljs-keyword">my</span> <span class="hljs-type">$template</span> = <span class="hljs-type">$c</span>-><span class="hljs-type">session</span>->{name} ? '<span class="hljs-string">list</span>' : '<span class="hljs-str...
<span class="hljs-type">$c</span>-><span class="hljs-type">render</span>(<span class="hljs-type">$template</span>);
});
<span class="hljs-type">$r</span>-><span class="hljs-type">get</span>('<span class="hljs-string">/list/:name</span>')->to(template => '<span class="hljs-string">list</span>')->name('<span class="hljs-string">list</sp...
<span class="hljs-type">$r</span>-><span class="hljs-type">get</span>('<span class="hljs-string">/add</span>')->to('<span class="hljs-string">List#show_add</span>')->name('<span class="hljs-string">show_add</span>')...
<span class="hljs-type">$r</span>-><span class="hljs-type">post</span>('<span class="hljs-string">/add</span>')->to('<span class="hljs-string">List#do_add</span>')->name('<span class="hljs-string">do_add</span>');
<span class="hljs-type">$r</span>-><span class="hljs-type">post</span>('<span class="hljs-string">/update</span>')->to('<span class="hljs-string">List#update</span>')->name('<span class="hljs-string">update</span>')...
<span class="hljs-type">$r</span>-><span class="hljs-type">post</span>('<span class="hljs-string">/remove</span>')->to('<span class="hljs-string">List#remove</span>')->name('<span class="hljs-string">remove</span>')...
<span class="hljs-type">$r</span>-><span class="hljs-type">post</span>('<span class="hljs-string">/login</span>')->to('<span class="hljs-string">Access#login</span>')->name('<span class="hljs-string">login</span>');
<span class="hljs-type">$r</span>-><span class="hljs-type">any</span>('<span class="hljs-string">/logout</span>')->to('<span class="hljs-string">Access#logout</span>')->name('<span class="hljs-string">logout</span>'...
}
<span class="hljs-number">1</span>;
</code></pre>
<p><small>lib/Wishlist.pm</small></p>
devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/17/day-17-the-wishlist-app/index.html" rel="prev"><strong>Previous Article</strong> Day 17: The Wishlist App</a></li>
<li class="next"><a href="/blog/2017/12/19/day-19-make-your-app-installable/index.html" rel="next"><strong>Next Article</strong> Day 19: Make Your App Installable </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_19_day-19-make-your-app-installable view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 19: Make Your App Installable</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-19">Dec 19, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Container ship loading at the dock" src="/blog/2017/12/19/day-19-make-your-app-installable/container_ship.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Thus far we have always run our applications from the local directory.
That is usually the project root directory and/or the repository checkout.
But did you know that with only a few changes you can make your application installable like other Perl modules?</p>
<p>While, you must do this if you want to upload your application to CPAN, even if you don't intend to do that, it still has benefits.
You can install the application on your personal computer, especially if you want to be able to run the script while in other directories.
Having an installable module also means that you can use a so-called "DarkPAN" and related tools to build yourself a local "CPAN".
If you have multiple Perl modules at your company (or as part of any project) using a DarkPAN can ease integration and deployment immensely!
devdata/https_mojolicious.io_blog_2017_12_19_day-19-make-your-app-installable view on Meta::CPAN
The major innovation that makes this method possible and so painless is the module <a href="https://metacpan.org/pod/File::Share">File::Share</a>.
While it isn't <a href="https://metacpan.org/pod/File::ShareDir">the original module</a> used to locate share directories after installation, it is the best one since it also works before hand during development too.
To do so it uses the heuristic of looking to see if a directory exists named <code>share</code> in that particular location (and a few checks for sanity), thus the second reason we call the directory that.</p>
<p>When used we get the absolute path to the share directory of your distribution.
Usually the name of the distribution is the name of your main module with the <code>::</code> replaced by <code>-</code>.</p>
<h2>Use in Mojolicious Apps</h2>
<p>To use File::Share in a Mojolicious (Full) app I recommend wrapping it in a <a href="http://mojolicious.org/perldoc/Mojo/File">Mojo::File</a> object and storing it in an attirbute on the app.
The attribute can be named anything, perhaps even as simple as <code>files</code>, though for the <a href="https://github.com/jberger/Wishlist/blob/blog_post/installable/lib/Wishlist.pm#L10-L14">Wishlist app</a> I have used the name <code>dist_dir</c...
<p>Why <code>dist_dir</code>?
Well that is the name of the function provided by File::Share.</p>
<pre><code>package Wishlist;
use Mojo::Base 'Mojolicious';
...
use File::Share;
devdata/https_mojolicious.io_blog_2017_12_19_day-19-make-your-app-installable view on Meta::CPAN
unshift @{ $app->renderer->paths }, $templates;
}
</code></pre>
<p>Note that you could use that kind of process to allow other configured files to be relative to the home.
The application home is a great place to put data like a sqlite database; the sqlite database file seen earlier, which as show had to be an absolute path.
Indeed such a transform exists already exists in the Wishlist app but was omitted above for clarity.</p>
<h2>In Conclusion</h2>
<p>I have made some of these changes to the <a href="https://github.com/jberger/Wishlist/compare/blog_post/sqlite_model...blog_post/installable">Wishlist App</a>.
You'll see that it it really isn't much to do.</p>
<p>You also see that I only used as much of these instructions as I needed; you can do the same.
There is no magic in any of what you've seen (other than perhaps File::Share).
If you don't need to think about theming or customizing the environment variable, then don't worry about it.
But if you find yourself in that situation, you'll know you can make such features available to your users.</p>
<p>And hey, if it is a useful application, consider uploading it to CPAN.
Though I warn you, once you start contributing to CPAN it can be addictive!</p>
devdata/https_mojolicious.io_blog_2017_12_19_day-19-make-your-app-installable view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/18/day-18-the-wishlist-model/index.html" rel="prev"><strong>Previous Article</strong> Day 18: The Wishlist Model</a></li>
<li class="next"><a href="/blog/2017/12/20/day-20-practical-testing/index.html" rel="next"><strong>Next Article</strong> Day 20: Practical Testing </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_20_day-20-practical-testing view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 20: Practical Testing</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-20">Dec 20, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Taking a sample of lava at Kilauea" src="/blog/2017/12/20/day-20-practical-testing/lava.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Back on <a href="/blog/2017/12/09/day-9-the-best-way-to-test">Day 9</a> we discussed testing and especially <a href="http://mojolicious.org/perldoc/Test/Mojo">Test::Mojo</a>.
Today I want to just briefly talk about some practical things that can come up when testing real world applications.
Once again the discussion will be motivated by the <a href="https://github.com/jberger/Wishlist">Wishlist</a> application that we've been developing these past few days.</p>
</section>
<section id="section-2">
<h2>Configuration Overrides</h2>
devdata/https_mojolicious.io_blog_2017_12_20_day-20-practical-testing view on Meta::CPAN
title => '<span class="hljs-string">Dark Matter</span>',
url => '<span class="hljs-string">lordnibbler.org</span>',
},
],
}, '<span class="hljs-string">correct initial user state</span>';
done_testing;
</code></pre>
<p><small><a href="https://github.com/jberger/Wishlist/blob/blog_post/practical_testing/t/model.t">t/model.t</a></small></p>
<p>When called this way the passed hashref is loaded into the configuration rather than any configuration file.
Because of the way the <a href="https://github.com/jberger/Wishlist/blob/blog_post/practical_testing/lib/Wishlist.pm#L20-L26"><code>sqlite</code></a> attribute initializer was coded, the Mojo::SQLite special literal <code>:temp:</code> is passed thro...
Now I would never suggest that you write any code into your application that is specific to testing, however it is entirely reasonable to code around special literals that someone might need.
You could of course start a Wishlist server using a temporary database.</p>
<p>SQLite's in-memory (and Mojo::SQLite's on-disk temporary) databases are really handy for testing because they are automatically testing in isolation.
You don't have to worry about overwriting the existing database nor clearing the data at the end of your test.
Further, you can run your tests in <a href="https://metacpan.org/pod/Test::Harness#j<n>">parallel</a> to get a nice speedup in large test suites.</p>
<p>For databases that require a running server you have to be a little more careful, however isolated testing is still very possible.
For example, in Mojo::Pg you can set a <a href="http://mojolicious.org/perldoc/Mojo/Pg#search_path"><code>search_path</code></a> which isolates your test.</p>
<pre><code>my $t = Test::Mojo->new(
'MyApp',
{database => 'postgresql:///test?search_path=test_one'}
);
$pg->db->query('drop schema if exists test_one cascade');
$pg->db->query('create schema test_one');
...
$pg->db->query('drop schema test_one cascade');
</code></pre>
<p>You might have to be careful about when the migration happens too (ie disable <code>auto_migrate</code> and run it manually).
Also this will only isolate the tests per-name, here <code>test_one</code>.
Therefore I recommend you name the path for the name of the test file, this should be both descriptive and unique.
devdata/https_mojolicious.io_blog_2017_12_20_day-20-practical-testing view on Meta::CPAN
<p>If you have done any testing you've probably dealt with mocking, but if you haven't, mocking is the act of replacing functionality from essentially unrelated code with test-specific code.
Doing this lets you test one section of code (called a unit) in isolation from others.</p>
<p>Everyone has their favorite mock library.
There are so many tastes and styles that in the end Many people make their own, including <a href="https://metacpan.org/pod/Mock::MonkeyPatch">yours truly</a>.
Of course you can use those libraries in Mojolicious when appropriate.
As I mentioned before you can also mock out services by attaching tiny Mojolicious applications to a UserAgent's <a href="http://mojolicious.org/perldoc/Mojo/UserAgent#server"><code>server</code></a> attribute or making an entire external service...
<p>In some cases however, the natural place to mock is in the place of a helper.
When you think about it, this is actually rather obvious since helpers are often the glue used in Mojolicious applications to combine disparate code, like models or in this case the <a href="https://github.com/jberger/Wishlist/blob/blog_post/practica...
<p>To test this we could actually do any of the mentioned options from mocking <a href="https://metacpan.org/pod/LinkEmbedder#get">LinkEmbedder->get</a> to attaching a mock service.
That said it is sufficient here to just replace the helper, which is as easy as assigning over it.</p>
<pre><code class="hljs"><span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::Base</span> -strict;
<span class="hljs-keyword">use</span> <span class="hljs-function">Test::More</span>;
<span class="hljs-keyword">use</span> <span class="hljs-function">Test::Mojo</span>;
<span class="hljs-keyword">my</span> <span class="hljs-type">$t</span> = <span class="hljs-function">Test::Mojo</span>->new(
devdata/https_mojolicious.io_blog_2017_12_20_day-20-practical-testing view on Meta::CPAN
->element_exists(
'<span class="hljs-string">form input[type="hidden"][name="url"][value="coolbeans.notasite"]</span>'
);
is <span class="hljs-type">$url</span>, '<span class="hljs-string">coolbeans.notasite</span>', '<span class="hljs-string">correct site was requested</span>';
done_testing;
</code></pre>
<p><small><a href="https://github.com/jberger/Wishlist/blob/blog_post/practical_testing/t/embed.t">t/embed.t</a></small></p>
<p>Because the template expects the result to be an object we have to build a tiny class to contain our mock results.
Also whenever you are mocking, it is important to check the input your mock received as well as the results that the calling code derives from your mock return value.</p>
<p>In the test you can also see some examples of how to use selectors to test for both text and attribute values.
The text test is especially important because it shows that the html value that I got back from the LinkEmbedder isn't being escaped by the template and will render as HTML to the client.</p>
<p>A few more tests and some documentation and our application will really be taking final shape!</p>
</section>
devdata/https_mojolicious.io_blog_2017_12_20_day-20-practical-testing view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/19/day-19-make-your-app-installable/index.html" rel="prev"><strong>Previous Article</strong> Day 19: Make Your App Installable</a></li>
<li class="next"><a href="/blog/2017/12/21/day-21-virtually-a-lumberjack/index.html" rel="next"><strong>Next Article</strong> Day 21: Virtual(ly a) Lumberjack </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_21_day-21-virtually-a-lumberjack view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 21: Virtual(ly a) Lumberjack</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-21">Dec 21, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Woman wearing VR goggles outside" src="/blog/2017/12/21/day-21-virtually-a-lumberjack/vr.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>What do you do when you want to split up a stream of data in real-time while
giving the user instructions?</p>
<p>This is just what I wanted to do to aid in reverse-engineering the USB
protocol of Virtual Reality devices known as Head Mounted Displays (HMD), for
the <a href="http://www.openhmd.net/">OpenHMD</a> project.</p>
<p>HMDs are used to create virtual reality environments. When worn, two slightly
devdata/https_mojolicious.io_blog_2017_12_21_day-21-virtually-a-lumberjack view on Meta::CPAN
<img alt="author image" src="/static/avatar_candyangel.jpg">
</div>
<div class="about">
<h5>CandyAngel</h5>
<p>CandyAngel is a Perl developer who tends to demonstrate her love of any particular piece of software by making it do things it was never intended to do.. yet still do it well.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/20/day-20-practical-testing/index.html" rel="prev"><strong>Previous Article</strong> Day 20: Practical Testing</a></li>
<li class="next"><a href="/blog/2017/12/22/day-22-how-to-build-a-public-rest-api/index.html" rel="next"><strong>Next Article</strong> Day 22: A RESTful API with OpenAPI </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 22: A RESTful API with OpenAPI</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-22">Dec 22, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="A hammock on a beach" src="/blog/2017/12/22/day-22-how-to-build-a-public-rest-api/hammock_beach.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>The <a href="https://www.openapis.org/">OpenAPI</a> Specification (formerly named
Swagger) is an API description format for REST APIs. An API specification
written using the the rules set by the Open API Initiative can be used to
describe:</p>
<ul>
<li>All the available endpoints. An endpoint is a unique resource that can
access or modify a given object.</li>
<li>Input parameters, such as headers, query parameters and/or body parameters.</li>
<li>The structure of the response, including headers status codes and the body -
if any.</li>
<li>Authentication methods</li>
<li>Contact information, license, terms of use and other information</li>
</ul>
<p>This post look into how to write an API specification and how to use it
together with
<a href="https://metacpan.org/pod/Mojolicious::Plugin::OpenAPI">Mojolicious::Plugin::OpenAPI</a>
and <a href="https://metacpan.org/pod/OpenAPI::Client">OpenAPI::Client</a>.</p>
</section>
<section id="section-2">
<h2>Why would you use OpenAPI</h2>
<p>This question comes up quite often after telling people about OpenAPI:
"but...why?" The people asking this often come from the same background as
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api view on Meta::CPAN
<h2>How to write the specification</h2>
<p>Some people like to generate the specification from code, but I truly believe
that writing the specification by hand and the generate code is the right way
to do it. The reasoning behind this is "seperation of concern": Having the
specification in a common format (JSON or YAML) allow other non-perl developer
to contribute and read the document.</p>
<p>The API need to follow the rules set by the
<a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md">OpenAPI specification</a>.
In this post we will use the 2.0 version, but version
<a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md">3.0</a>
will be available soon, so you might consider looking at that as well.</p>
<p>Here is an example API, written in YAML:</p>
<pre><code>swagger: '2.0'
info:
version: '0.42'
title: Dummy example
schemes: [ http ]
basePath: "/api"
paths:
/echo:
post:
x-mojo-to: "echo#index"
operationId: echo
parameters:
- in: body
name: body
schema:
type: object
responses:
200:
description: Echo response
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api view on Meta::CPAN
</code></pre>
<p>There's a bunch of things to dive into, but here is a quick overview:</p>
<ul>
<li><code>swagger</code> is just to specify the version of the spec</li>
<li><code>info</code> is to give some meta-information about the API</li>
<li><code>schemes</code> is a list of valid HTTP schemes that can be used to access the API</li>
<li>All the resources under <code>paths</code> will be relative to <code>basePath</code>, meaning that
you need to use <code>/api/echo</code> to access the "echo" resource.</li>
<li>The key <code>post</code> under <code>/echo</code> tells you which HTTP method you need to use to
access the resource.</li>
<li><code>x-mojo-to</code> is specific for
<a href="https://metacpan.org/pod/Mojolicious::Plugin::OpenAPI">Mojolicious::Plugin::OpenAPI</a>,
and will be passed on to the route's
<a href="https://metacpan.org/pod/Mojolicious::Routes::Route#to">to()</a> method.</li>
<li><code>operationId</code> is used by
<a href="https://metacpan.org/pod/OpenAPI::Client">OpenAPI::Client</a> and other
clients to generate a method that can be used to access the resource from
the client side.</li>
<li><code>parameters</code> and <code>responses</code> contains a description of the acceptable input
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api view on Meta::CPAN
# Render back the same data as you received using the "openapi" handler
$self->render(openapi => $self->req->json);
}
1;
</code></pre>
<p>Last, you should update the test. Change <code>t/basic.t</code> so the line with
<code>get_ok</code> reads:</p>
<pre><code>$t->post_ok('/api/echo', '{"i":"work"}')->status_is(200)->json_is({i=>"work"});
</code></pre>
<p>Check it all works right:</p>
<pre><code>$ prove -l t
</code></pre>
<p>And you're done creating an OpenAPI powered application!</p>
<h2>Running your application</h2>
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api view on Meta::CPAN
<img alt="author image" src="https://secure.gravatar.com/avatar/806800a3aeddbad6af673dade958933b">
</div>
<div class="about">
<h5>Jan Henning Thorsen</h5>
<p>Jan (aka batman) is a self taught Perl hacker and a member of the Mojolicious Core Team. He likes to work with anything that has to do with web - both frontend and backend. Got more questions? Send him an <a href="mailto:jh...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/21/day-21-virtually-a-lumberjack/index.html" rel="prev"><strong>Previous Article</strong> Day 21: Virtual(ly a) Lumberjack</a></li>
<li class="next"><a href="/blog/2017/12/23/day-23-one-liners-for-fun-and-profit/index.html" rel="next"><strong>Next Article</strong> Day 23: One-Liners for Fun and Profit </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 23: One-Liners for Fun and Profit</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-23">Dec 23, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Old man playing timed chess" src="/blog/2017/12/23/day-23-one-liners-for-fun-and-profit/chess.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Perl is well-known for its <a href="http://www.catonmat.net/download/perl1line.txt">one-liners</a>: short programs written as part of the <a href="http://perldoc.perl.org/perlrun.html">command line invocation of the interpreter</...
Certainly every programmer or sysadmin has the need, from time to time, to do a quick one-off task programmatically.
Such tasks can be done with a full script, to be sure, but once you get the hang of writing them, one-liners can save the time and hassle of actually doing so.</p>
<p>These tasks may include removing unwanted lines from files, collecting data from logs, or even a quick proof-of-concept of something that would become a script later.
They can read lines in files, even multiple files, can operate on files in-place, can read from STDIN as a pipe.
But while one-liners have been tools of the trade for these activities, certainly no such thing would be practical for web tasks, right?</p>
devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit view on Meta::CPAN
So could we take this further?</p>
<p>Could we do remote data fetching and manipulation as a one-liner?
Could we build an entire web application as a one-liner?
Would I be asking if the answer was no?</p>
</section>
<section id="section-2">
<h2>A Note on Readability</h2>
<p>Almost always when I post articles on Mojolicious, I'm keenly aware of Perl's reputation for readability.
I firmly believe that Perl can be written to be easily read, it just takes awareness from the author.
But every now and again you need to have a little fun!</p>
<p>One-liners are not meant for too much reuse.
Their value is the extreme rapidity of their creation and as such they are terse.
If they were well-formed scripts, well, you'd put them in a file.</p>
<p>So please, if this is the first time you see Perl and Mojolicious, I want you to know that this is the exception and not the rule!</p>
<h2>The Key ... words?</h2>
devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit view on Meta::CPAN
But when combined with others, you can start to have fun.</p>
<h3>Making Requests</h3>
<p>Most of the functions are dedicated to making HTTP requests.
There are functions for</p>
<ul>
<li>get - <code>g</code></li>
<li>head - <code>h</code></li>
<li>post - <code>p</code></li>
<li>put - <code>u</code></li>
<li>patch - <code>t</code></li>
<li>delete - <code>d</code></li>
<li>options - <code>o</code></li>
</ul>
<p>These are just their respective calls on <a href="http://mojolicious.org/perldoc/Mojo/UserAgent">Mojo::UserAgent</a> with the one space-saving optimization that they return the <a href="http://mojolicious.org/perldoc/Mojo/Message/Response">Respons...
<p>A simple use could be to fetch the title from a webpage.</p>
devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit view on Meta::CPAN
<p>You can also use Perl's looping constructs.
Perhaps you have a file full of sites for which you want to get some data.</p>
<pre><code>$ cat sites
mojolicious.org
mojolicious.io
mojocasts.com
</code></pre>
<p>You can then take each line, request it, and post-processes.</p>
<pre><code>perl -Mojo -nlE 'say g($_)->dom->at("title")->text' sites
</code></pre>
<h3>Object Constructors</h3>
<p>The Mojo toolkit contains many helpful classes.
The ojo functions provide quick constructors for them, so you can access their functionality without all the typing!</p>
<ul>
devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/22/day-22-how-to-build-a-public-rest-api/index.html" rel="prev"><strong>Previous Article</strong> Day 22: A RESTful API with OpenAPI</a></li>
<li class="next"><a href="/blog/2017/12/24/day-24-release-and-wrap-up/index.html" rel="next"><strong>Next Article</strong> Day 24: Release and Wrap-Up </a></li>
</ul>
</div>
</article>
</div>
devdata/https_mojolicious.io_blog_2017_12_24_day-24-release-and-wrap-up view on Meta::CPAN
</div>
<div class="content-outer">
<div class="row" id="page-content">
<div class="eight columns" id="primary">
<article class="post">
<div class="entry-header cf">
<h1>Day 24: Release and Wrap-Up</h1>
<p class="post-meta">
<time class="date" datetime="2017-12-24">Dec 24, 2017</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Out of focus image of lit Christmas tree" src="/blog/2017/12/24/day-24-release-and-wrap-up/tree_unfocused.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Over the course of this advent calendar, we have discussed the <a href="https://mojolicious.io/blog/tag/wishlist/">Wishlist example application</a> several times.
We used it to motivate discussions about <a href="/blog/2017/12/17/day-17-the-wishlist-app/">templates</a>, <a href="/blog/2017/12/18/day-18-the-wishlist-model/">models</a>, <a href="/blog/2017/12/19/day-19-make-your-app-installable/">installable app...
In this post I want to use it somewhat differently.
I would like to motivate you, the reader, into action in a few different ways.</p>
</section>
<section id="section-2">
<h3>The Double-Edged Sword</h3>
<p>The internet has made so many amazing things possible.
Old friendships are kept alive.
Personal photographs can be stored forever and shared with friends.
Rare items can be discussed, found, and purchased.
devdata/https_mojolicious.io_blog_2017_12_24_day-24-release-and-wrap-up view on Meta::CPAN
<p>And if not, I hope you'll enjoy what they are or what they will be.</p>
<h2>Wrapping Up</h2>
<p>I have had so much fun producing this Advent Calendar for you.
I hope you have enjoyed it too.
Thank you so much for reading along with me!
Please refer back to it as needed and share it with friends and coworkers if and when it can help others learn and use Mojolicious.</p>
<p>I want to thank the guest authors who have contributed posts</p>
<ul>
<li>Doug Bell - preaction (<a href="https://twitter.com/preaction">twitter</a>/<a href="https://metacpan.org/author/PREACTION">CPAN</a>/<a href="https://github.com/preaction">GitHub</a>/<a href="http://preaction.me/">web</a>)</li>
<li>Ed J - mohawk (<a href="https://metacpan.org/author/ETJ">CPAN</a>/<a href="https://github.com/mohawk2">GitHub</a>)</li>
<li>CandyAngel (<a href="https://twitter.com/CandyAngel_Nay">twitter</a>/<a href="https://metacpan.org/author/EJUNGLE">CPAN</a>/<a href="https://github.com/CandyAngel">GitHub</a>)</li>
<li>Jan Henning Thorsen - batman (<a href="https://twitter.com/jhthorsen">twitter</a>/<a href="https://metacpan.org/author/JHTHORSEN">CPAN</a>/<a href="https://github.com/jhthorsen">GitHub</a>/<a href="http://thorsen.pm/">web</a>)</li>
</ul>
<p>Without their contributions, this series would have just been me rambling.
Thank you so very much!</p>
devdata/https_mojolicious.io_blog_2017_12_24_day-24-release-and-wrap-up view on Meta::CPAN
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2017/12/23/day-23-one-liners-for-fun-and-profit/index.html" rel="prev"><strong>Previous Article</strong> Day 23: One-Liners for Fun and Profit</a></li>
<li class="next"><a href="/blog/2018/03/18/graphql-openapi/index.html" rel="next"><strong>Next Article</strong> Mojolicious, OpenAPI - and GraphQL </a></li>
</ul>
</div>
</article>
</div>