view release on metacpan or search on metacpan
devdata/https_mojolicious.io_blog_2017_12_12_day-12-more-than-a-base-class
devdata/https_mojolicious.io_blog_2017_12_13_day-13-more-about-roles
devdata/https_mojolicious.io_blog_2017_12_14_day-14-you-promised-to-call
devdata/https_mojolicious.io_blog_2017_12_15_day-15-start-a-new-yancy-app
devdata/https_mojolicious.io_blog_2017_12_16_day-16-the-secret-life-of-sessions
devdata/https_mojolicious.io_blog_2017_12_17_day-17-the-wishlist-app
devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model
devdata/https_mojolicious.io_blog_2017_12_19_day-19-make-your-app-installable
devdata/https_mojolicious.io_blog_2017_12_20_day-20-practical-testing
devdata/https_mojolicious.io_blog_2017_12_21_day-21-virtually-a-lumberjack
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api
devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit
devdata/https_mojolicious.io_blog_2017_12_24_day-24-release-and-wrap-up
devscripts/update
dist.ini
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_01.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_02.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_03.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_04.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_05.pm
devdata/https_mojolicious.io_blog_2017_12_08_day-8-mocking-a-rest-api view on Meta::CPAN
<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
data.</p>
<p>It would be a lot easier to set up a mock public API that I could use to
test my UI, and it turns out that Mojolicious makes this very easy.</p>
</section>
<section id="section-2">
<p>So let's set up a simple Mojolicious::Lite app that responds to a path
with a JSON response:</p>
<pre><code class="hljs"><span class="hljs-comment"># test-api.pl</span><span class="hljs-comment">
</span><span class="hljs-keyword">use</span> <span class="hljs-function">Mojolicious::Lite</span>;
get '<span class="hljs-string">/servers</span>' => <span class="hljs-keyword">sub </span>{
devdata/https_mojolicious.io_blog_2017_12_11_day-11-useragent-content-generators view on Meta::CPAN
</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.
In a larger code base, that adherence to the DRY mantra (Don't Repeat Yourself) might be invaluable.</p>
</section>
<small><p><a href="http://www.publicdomainpictures.net/view-image.php?image=157945&picture=artist-painting">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/useragent/">useragent</a>
</p>
<div class="bio cf">
devdata/https_mojolicious.io_blog_2017_12_15_day-15-start-a-new-yancy-app view on Meta::CPAN
</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>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/app/">app</a>
</p>
<div class="bio cf">
devdata/https_mojolicious.io_blog_2017_12_19_day-19-make-your-app-installable view on Meta::CPAN
While that's true, it makes its recommendations without using external modules and for one specific installation tool.
It also assumes that your application <a href="http://mojolicious.org/perldoc/Mojolicious#home"><code>home</code></a> should be related to the installation directory, which isn't always the case.</p>
<p>Yours truly has even written a <a href="https://metacpan.org/pod/Mojolicious::Plugin::InstallablePaths">module</a> that was intended to ease this process somewhat.
While it does that, and I don't intend to deprecate it, I think there are even easier patterns now.</p>
<h2>The Share Directory</h2>
<p>Perl has a lesser known and somewhat informal functionality for bundling static files called a "share directory".
Create a directory in your project root called <code>share</code> which will serve for this purpose.
Then move the <code>templates</code> and <code>public</code> directories from your project root into that directory.
You should also move any other static files like say database migration files (e.g. <code>wishlist.sql</code> from <a href="https://mojolicious.io/blog/2017/12/18/day-18-the-wishlist-model/">yesterday</a>).</p>
<p>Although each install tool has different ways of specifying where the share directory is located during the development phase, none is espectially difficult to work with.
One reason I chose the name <code>share</code> is because my preferred installation tool <a href="https://metacpan.org/pod/Module::Build::Tiny">Module::Build::Tiny</a> (which I use via <a href="https://metacpan.org/pod/App::ModuleBuildTiny">App::Modu...
The others are configurable in the install scripts themselves (Makefile.PL/Build.PL/dist.ini).
For <a href="https://metacpan.org/pod/Module::Build">Module::Build</a>, you set the <a href="https://metacpan.org/pod/Module::Build::API#share_dir"><code>share_dir</code></a> parameter</p>
<pre><code>share_dir => 'share'
</code></pre>
devdata/https_mojolicious.io_blog_2017_12_19_day-19-make-your-app-installable view on Meta::CPAN
return $sqlite;
};
sub startup {
my $app = shift;
$app->renderer->paths([
$app->dist_dir->child('templates'),
]);
$app->static->paths([
$app->dist_dir->child('public'),
]);
...
}
</code></pre>
<h2>What About The App Home?</h2>
<p>So far we have been focusing on bundled static files.
As we saw in the Cookbook entry, one other consideration for installable applications is its <code>home</code>.</p>
devdata/https_mojolicious.io_blog_2017_12_21_day-21-virtually-a-lumberjack view on Meta::CPAN
<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>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@jhthorsen" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2017/12/22/day-22-how-to-build-a-public-rest-api/" property="og:url">
<meta content="Day 22: A RESTful API with OpenAPI" property="og:title">
<meta content="How to build a public REST API for your Mojolicious application" property="og:description">
<meta content="https://mojolicious.io/blog/2017/12/22/day-22-how-to-build-a-public-rest-api/hammock_beach.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 22: A RESTful API with OpenAPI - mojolicious.io</title>
<meta content="Jan Henning Thorsen" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api view on Meta::CPAN
<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>
devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api view on Meta::CPAN
</code></pre>
<p>After that, edit <code>lib/MyApp.pm</code> to make it look like this:</p>
<pre><code>package MyApp;
use Mojo::Base "Mojolicious";
sub startup {
my $self = shift;
# Load the "api.yaml" specification from the public directory
$self->plugin(OpenAPI => {spec => $self->static->file("api.yaml")->path});
}
1;
</code></pre>
<p>Then copy/paste the specification from above and save it to <code>public/api.yaml</code>.</p>
<p>Next you must create a controller <code>lib/MyApp/Controller/Echo.pm</code> to match
<code>x-mojo-to</code> in the API specification:</p>
<pre><code>package MyApp::Controller::Echo;
use Mojo::Base "Mojolicious::Controller";
sub index {
# Validate input request or return an error document
my $self = shift->openapi->valid_input or return;
devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit view on Meta::CPAN
<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>
devscripts/update view on Meta::CPAN
"12" => "https://mojolicious.io/blog/2017/12/12/day-12-more-than-a-base-class",
"13" => "https://mojolicious.io/blog/2017/12/13/day-13-more-about-roles",
"14" => "https://mojolicious.io/blog/2017/12/14/day-14-you-promised-to-call",
"15" => "https://mojolicious.io/blog/2017/12/15/day-15-start-a-new-yancy-app",
"16" => "https://mojolicious.io/blog/2017/12/16/day-16-the-secret-life-of-sessions",
"17" => "https://mojolicious.io/blog/2017/12/17/day-17-the-wishlist-app",
"18" => "https://mojolicious.io/blog/2017/12/18/day-18-the-wishlist-model",
"19" => "https://mojolicious.io/blog/2017/12/19/day-19-make-your-app-installable",
"20" => "https://mojolicious.io/blog/2017/12/20/day-20-practical-testing",
"21" => "https://mojolicious.io/blog/2017/12/21/day-21-virtually-a-lumberjack",
"22" => "https://mojolicious.io/blog/2017/12/22/day-22-how-to-build-a-public-rest-api",
"23" => "https://mojolicious.io/blog/2017/12/23/day-23-one-liners-for-fun-and-profit",
"24" => "https://mojolicious.io/blog/2017/12/24/day-24-release-and-wrap-up",
);
gen_curried_sub(
'App::CreateAcmeCPANModulesImportModules::create_acme_cpanmodules_import_modules',
{
modules => [
{
name => '2017',
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_22.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2017_12_22;
our $DATE = '2018-12-30'; # DATE
our $VERSION = '0.001'; # VERSION
our $LIST = {description=>"This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2017/12/22/day-22-how-to-build-a-public-rest-api] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{modul...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2017 (day 22)
__END__
=pod
=encoding UTF-8
=head1 NAME
Acme::CPANModules::Import::MojoliciousAdvent::2017_12_22 - Modules mentioned in Mojolicious Advent Calendar 2017 (day 22)
=head1 VERSION
This document describes version 0.001 of Acme::CPANModules::Import::MojoliciousAdvent::2017_12_22 (from Perl distribution Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017), released on 2018-12-30.
=head1 DESCRIPTION
This module is generated by extracting module names mentioned in L<https://mojolicious.io/blog/2017/12/22/day-22-how-to-build-a-public-rest-api> (retrieved on 2018-12-30). Visit the URL for the full contents.
Modules mentioned in Mojolicious Advent Calendar 2017 (day 22).
This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2017/12/22/day-22-how-to-build-a-public-rest-api] (retrieved on 2018-12-30). Visit the URL for the full contents.
=head1 INCLUDED MODULES
=over
=item * L<JSON::Validator>
=item * L<Mojolicious::Command::generate::app>
=item * L<Mojolicious::Command::routes>