Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017

 view release on metacpan or  search on metacpan

META.json  view on Meta::CPAN

            "Dist::Zilla" : "0",
            "Dist::Zilla::Plugin::ShareDir" : "0",
            "ExtUtils::MakeMaker" : "0",
            "File::Share" : "0",
            "File::ShareDir" : "0",
            "File::ShareDir::Install" : "0",
            "FindBin" : "0",
            "Galileo" : "0",
            "GraphQL" : "0",
            "IO::Socket::SSL" : "0",
            "JSON::Validator" : "0",
            "LinkEmbedder" : "0",
            "List::UtilsBy" : "0",
            "Minion" : "0",
            "Mock::MonkeyPatch" : "0",
            "Module::Build" : "0",
            "Module::Build::Tiny" : "0",
            "Mojo::Asset::File" : "0",
            "Mojo::Autobox" : "0",
            "Mojo::Base" : "0",
            "Mojo::ByteStream" : "0",
            "Mojo::Collection" : "0",
            "Mojo::Collection::Role::UtilsBy" : "0",
            "Mojo::DOM" : "0",
            "Mojo::DOM::CSS" : "0",
            "Mojo::DOM::Role::PrettyPrinter" : "0",
            "Mojo::File" : "0",
            "Mojo::Home" : "0",
            "Mojo::IOLoop" : "0",
            "Mojo::IOLoop::Stream" : "0",
            "Mojo::JSON" : "0",
            "Mojo::JSON::Pointer" : "0",
            "Mojo::Loader" : "0",
            "Mojo::Log::Role::Clearable" : "0",
            "Mojo::Message::Request" : "0",
            "Mojo::Message::Response" : "0",
            "Mojo::Pg" : "0",
            "Mojo::Pg::Migrations" : "0",
            "Mojo::Promise" : "0",
            "Mojo::SQLite" : "0",
            "Mojo::SQLite::Results" : "0",
            "Mojo::Template" : "0",

META.json  view on Meta::CPAN

            "Mojolicious::Command::routes" : "0",
            "Mojolicious::Command::test" : "0",
            "Mojolicious::Command::version" : "0",
            "Mojolicious::Commands" : "0",
            "Mojolicious::Controller" : "0",
            "Mojolicious::Lite" : "0",
            "Mojolicious::Plugin::ACME" : "0",
            "Mojolicious::Plugin::Config" : "0",
            "Mojolicious::Plugin::DefaultHelpers" : "0",
            "Mojolicious::Plugin::InstallablePaths" : "0",
            "Mojolicious::Plugin::JSONConfig" : "0",
            "Mojolicious::Plugin::OpenAPI" : "0",
            "Mojolicious::Plugin::ReplyTable" : "0",
            "Mojolicious::Plugin::TagHelpers" : "0",
            "Mojolicious::Plugin::Yancy" : "0",
            "Mojolicious::Renderer" : "0",
            "Mojolicious::Routes::Route" : "0",
            "Mojolicious::Sessions" : "0",
            "Mojolicious::Types" : "0",
            "Moo" : "0",
            "MooX::ChainedAttributes" : "0",

META.json  view on Meta::CPAN

            "class" : "Dist::Zilla::Plugin::CopyrightYearFromGit",
            "name" : "@Author::PERLANCAR/CopyrightYearFromGit",
            "version" : "0.003"
         },
         {
            "class" : "Dist::Zilla::Plugin::IfBuilt",
            "name" : "@Author::PERLANCAR/IfBuilt",
            "version" : "0.03"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "@Author::PERLANCAR/MetaJSON",
            "version" : "6.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "@Author::PERLANCAR/MetaConfig",
            "version" : "6.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::Authority",
            "name" : "@Author::PERLANCAR/Authority",

META.json  view on Meta::CPAN

      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.010"
      }
   },
   "x_authority" : "cpan:PERLANCAR",
   "x_serialization_backend" : "Cpanel::JSON::XS version 3.0239",
   "x_static_install" : 1
}

META.yml  view on Meta::CPAN

      version: '0.011'
    -
      class: Dist::Zilla::Plugin::CopyrightYearFromGit
      name: '@Author::PERLANCAR/CopyrightYearFromGit'
      version: '0.003'
    -
      class: Dist::Zilla::Plugin::IfBuilt
      name: '@Author::PERLANCAR/IfBuilt'
      version: '0.03'
    -
      class: Dist::Zilla::Plugin::MetaJSON
      name: '@Author::PERLANCAR/MetaJSON'
      version: '6.010'
    -
      class: Dist::Zilla::Plugin::MetaConfig
      name: '@Author::PERLANCAR/MetaConfig'
      version: '6.010'
    -
      class: Dist::Zilla::Plugin::Authority
      name: '@Author::PERLANCAR/Authority'
      version: '1.009'
    -

devdata/https_mojolicious.io_blog_2017_12_05_day-5-your-apps-built-in-commands  view on Meta::CPAN

<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&#39;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&#39;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&#39;d like.
Because of that, headers are omitted from the output unless you pass <code>-v</code>.</p>

<p>Let&#39;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
</code></pre>

<p>You can fetch the Perl headlines from reddit.
To do so we fetch the url (following redirects with <code>-r</code>), then we give it a <a href="http://mojolicious.org/perldoc/Mojo/DOM/CSS">CSS3 selector</a>, and finally extract the text from each found element.</p>

<pre><code>mojo get -r reddit.com/r/perl &#39;p.title &gt; a.title&#39; text
</code></pre>

devdata/https_mojolicious.io_blog_2017_12_07_day-7-using-template-variants-for-a-beta-landing-page  view on Meta::CPAN

&lt;h1&gt;CPAN Testers&lt;/h1&gt;
&lt;p&gt;This is the main CPAN Testers application.&lt;/p&gt;
</code></pre>

<p>Template variants are a useful feature in some edge cases, and this isn&#39;t the
first time I&#39;ve found a good use for them. I&#39;ve also used them to provide a
different layout template in &quot;development&quot; mode to display a banner saying
&quot;You&#39;re on the development site&quot;. 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&#39;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>,

devdata/https_mojolicious.io_blog_2017_12_08_day-8-mocking-a-rest-api  view on Meta::CPAN

            </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
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&#39;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 &#39;<span class="hljs-string">/servers</span>&#39; =&gt; <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>-&gt;<span class="hljs-type">render</span>(
        json =&gt; [
            { ip =&gt; &#39;<span class="hljs-string">10.0.0.1</span>&#39;, os =&gt; &#39;<span class="hljs-string">Debian 9</span>&#39; },
            { ip =&gt; &#39;<span class="hljs-string">10.0.0.2</span>&#39;, os =&gt; &#39;<span class="hljs-string">Debian 8</span>&#39; }
        ],
    );
};
app-&gt;start;
</code></pre>

<p>Now I can fetch that JSON response by starting the web application and
going to <code>/servers</code> or by using the <code>get</code> command:</p>

<pre><code>$ perl test-api.pl get /servers
[{&quot;ip&quot;:&quot;10.0.0.1&quot;,&quot;os&quot;:&quot;Debian 9&quot;},{&quot;ip&quot;:&quot;10.0.0.2&quot;,&quot;os&quot;:&quot;Debian 8&quot;}

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

<p>That&#39;s pretty easy and shows how easy Mojolicious can be to get started.

devdata/https_mojolicious.io_blog_2017_12_08_day-8-mocking-a-rest-api  view on Meta::CPAN


<p>Again, we can use the <code>get</code> command to test that we get the right data:</p>

<pre><code>$ perl test-api.pl get /servers
[
    { &quot;ip&quot;: &quot;10.0.0.1&quot;, &quot;os&quot;: &quot;Debian 9&quot; },
    { &quot;ip&quot;: &quot;10.0.0.2&quot;, &quot;os&quot;: &quot;Debian 8&quot; }
]
</code></pre>

<p>So now I can write a bunch of JSON in my script and it will be exposed
as an API. But I&#39;d like it to be easier to make lists of things: REST
APIs often have one endpoint as a list and another as an individual item
in that list. We can make a list by composing our individual parts using
Mojolicious templates and the <code>include</code> template helper:</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>;
any &#39;<span class="hljs-string">/*path</span>&#39; =&gt; <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>-&gt;<span class="hljs-type">render</span>(

devdata/https_mojolicious.io_blog_2017_12_08_day-8-mocking-a-rest-api  view on Meta::CPAN

{ &quot;ip&quot;: &quot;10.0.0.1&quot;, &quot;os&quot;: &quot;Debian 9&quot; }
@@ GET/servers/2.json.ep
{ &quot;ip&quot;: &quot;10.0.0.2&quot;, &quot;os&quot;: &quot;Debian 8&quot; }
@@ POST/servers.json.ep
{ &quot;status&quot;: &quot;success&quot;, &quot;id&quot;: 3, &quot;server&quot;: &lt;%== $c-&gt;req-&gt;body %&gt; }
@@ POST/servers.json+error.ep
% $c-&gt;res-&gt;code( 400 );
{ &quot;status&quot;: &quot;error&quot;, &quot;error&quot;: &quot;Bad request&quot; }
</code></pre>

<p>Now I have 20 lines of code that can be made to mock any JSON API
I write. Mojolicious makes everything easy!</p>

              </section>
              <small><p><a href="https://commons.wikimedia.org/w/index.php?curid=37564272">Image</a> by Calspan Corporation, National Highway Traffic Safety Administration - Public Domain.</p>
</small>

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

devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test  view on Meta::CPAN

              </div>

            <div class="post-content">

              <section id="section-1">
                  <p>Ok so it is a bit of a click-bait headline.
But that doesn&#39;t mean I don&#39;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&#39;ll give a quick overview of how to use Test::Mojo and some of its methods.
Rest assured you&#39;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

  my $app = shift;
  return Mojo::Pg-&gt;new($app-&gt;config-&gt;{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-&gt;new(&#39;MyApp&#39;, {pg =&gt; &#39;postgresql://testuser:testpass@/testdb&#39;});
</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&#39;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&#39;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();
my $t = Test::Mojo-&gt;new($app);
</code></pre>

devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test  view on Meta::CPAN

<p>Now that we have a running application and a tester to test it, what can we do?
The Mojolicious documentation has lots of examples both in the <a href="http://mojolicious.org/perldoc/Test/Mojo">class documenation</a> that we&#39;ve already seen and in the <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Testing">testin...
That said for the sake explication, let&#39;s see a few things.</p>

<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-&gt;get_ok(&#39;/login&#39;, {&#39;X-Application-Auth&#39; =&gt; &#39;custom value&#39;});
</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-&gt;post_ok(&#39;/login&#39;, form =&gt; {user =&gt; &#39;me&#39;, pass =&gt; &#39;secr3t&#39;});
$t-&gt;put_ok(&#39;/inventory/12345&#39;, json =&gt; {type =&gt; &#39;widget&#39;, value =&gt; &#39;tons&#39;});
</code></pre>

<p>Or you can submit raw data as a trailing argument</p>

<pre><code>use Mojo::XMLRPC &#39;encode_xmlrpc&#39;; # from CPAN
$t-&gt;post_ok(&#39;/xmlrpc&#39;, encode_xmlrpc(call =&gt; &#39;mymethod&#39;, &#39;myarg&#39;));

devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test  view on Meta::CPAN


<p>So what can we check?
We can check headers with <code>header_</code> etc, there is also a special <code>content_type_</code> family since that is often useful.
The <code>content_</code> methods check the raw data of the response, raw websocket messages can be tested with <code>message_</code>.</p>

<pre><code>$t-&gt;get_ok(&#39;/test.txt&#39;)
  -&gt;status_is(200)
  -&gt;content_like(qr/coal/);
</code></pre>

<p>There are methods for JSON.
HTTP requests responding with JSON can be tested with <code>json_</code>, websocket messages received containing JSON use <code>json_message_</code>.
The structure is tested using Test::More&#39;s <a href="https://metacpan.org/pod/Test::More#is_deeply"><code>is_deeply</code></a>.</p>

<pre><code>$t-&gt;get_ok(&#39;/santa_list/joel.json&#39;)
  -&gt;json_is({name =&gt; &#39;Joel Berger&#39;, status =&gt; &#39;nice&#39;});
</code></pre>

<p>These methods allow the (optional) first argument to be a <a href="http://mojolicious.org/perldoc/Mojo/JSON/Pointer">JSON Pointer</a> to &quot;dive in&quot; to the data structure.
Very handy when you only care about subsets of the data.</p>

<pre><code>$t-&gt;get_ok(&#39;/santa_list/joel.json&#39;)
  -&gt;json_is(&#39;/status&#39;, &#39;nice&#39;);
</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&#39;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-&gt;text_is(&#39;div.main-content p:nth-of-type(2)&#39;, &#39;This is the third paragraph of the main-section of text&#39;);
$t-&gt;element_exists(&#39;img[src=&quot;kitten.jpg&quot;]&#39;);
</code></pre>

<h2>Testing Websockets</h2>

devdata/https_mojolicious.io_blog_2017_12_10_day-10-give-the-customer-what-they-want  view on Meta::CPAN

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

<p>Mojolicious believes in <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Rendering#Content-negotiation">Content Negotiation</a>, as it is called, and supports it throughout the stack.
Mojolicious makes it easy and convenient for users to pick a format they would like.
Similarly it makes rendering the different formats easy on the site author, as you would expect.</p>

              </section>
              <section id="section-2">
                  <h2>Requesting a Format</h2>

<h3>Accept Headers</h3>

<p>The most HTTP-native way to choose a response format is with the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept"><code>Accept</code></a>.
A request bearing the <code>Accept: application/json</code> header is indicating it wants JSON in the response.
Mojolicious supports this header, and this format is very handy for programmatic API clients, but it isn&#39;t very friendly to users, so there are several other options.</p>

<h3>File Extension</h3>

<p>The first of these is via <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Routing#Formats">file extension</a>.
When defining a route, if you use the <code>:</code> placeholder you are opting-in to file-extension-based content negotiation.</p>

<pre><code>get &#39;/:name&#39; ...
</code></pre>

devdata/https_mojolicious.io_blog_2017_12_10_day-10-give-the-customer-what-they-want  view on Meta::CPAN

  my $data = [
    [qw/a b c d/],
    [qw/e f g h/],
  ];
  $c-&gt;reply-&gt;table($data);
};

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

<p>Of course under the hood this is using Content Negotiation and several other modules to provide CSV, HTML, JSON, text, XLS, and XLSX outputs.
It is configurable via several stash values that might be set.
If you&#39;d like to dig into that code to see how it works, please feel free.</p>

              </section>
              <small><p><a href="https://pxhere.com/en/photo/946984">Image</a> in the Public Domain.</p>
</small>

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

devdata/https_mojolicious.io_blog_2017_12_11_day-11-useragent-content-generators  view on Meta::CPAN

my $tx = $ua-&gt;build_tx(POST =&gt; &#39;/url&#39;);
$tx-&gt;req-&gt;headers-&gt;header(&#39;Content-Type&#39;, &#39;text/plain&#39;);
$tx-&gt;req-&gt;body(&#39;some binary content&#39;);
$ua-&gt;start($tx);
</code></pre>

<p>A Content Generators is a shortcut to help build requests for certain types of content.
The previous example wasn&#39;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-&gt;post(&#39;/url&#39;, json =&gt; {some =&gt; [&#39;json&#39;, &#39;data&#39;]});
</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 &#39;encode_json&#39;;
$ua-&gt;post(
  &#39;/url&#39;,
  {&#39;Content-Type&#39; =&gt; &#39;application/json&#39;},
  encode_json({some =&gt; [&#39;json&#39;, &#39;data&#39;]})
);
</code></pre>

<p>or a similar example to the above using <code>build_tx</code>.
I think you&#39;ll agree that the generator form is much easier to read and &quot;does what you mean&quot;.</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&#39;ve already seen.</p>

<p>The <code>form</code> generator creates urlencoded or multipart requests depending on the data passed.
The form generator is, unsurprisingly, useful for submittng forms, often used to login to sites, search for content or upload files.
It is even smart enought to use query parameters for <code>GET</code> and <code>HEAD</code> requests (which cannot take a body), while using body parameters for others.</p>

<p>Finally, the recently-added <code>multipart</code> generator is for building your own generic multipart requests.
Though not common, some APIs allow or even require users to upload multiple files in the same request.</p>

<p>This was the case presented to us by a user not too long ago.
They were interacting with the <a href="https://developers.google.com/drive/v3/web/multipart-upload">Google Drive API</a> that wanted them to upload a file as part of a multipart message with a JSON document attached containing metadata.
The overall request was to be marked at <a href="https://tools.ietf.org/html/rfc2387"><code>multipart/related</code></a> while each part should have its own <code>Content-Type</code>.
Google&#39;s documented example is</p>

<pre><code>POST https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart HTTP/1.1
Authorization: Bearer [YOUR_AUTH_TOKEN]
Content-Type: multipart/related; boundary=foo_bar_baz
Content-Length: [NUMBER_OF_BYTES_IN_ENTIRE_REQUEST_BODY]

--foo_bar_baz
Content-Type: application/json; charset=UTF-8

devdata/https_mojolicious.io_blog_2017_12_11_day-11-useragent-content-generators  view on Meta::CPAN

[JPEG_DATA]
--foo_bar_baz--
</code></pre>

<p>While this was possible using the lower level tools, we decided that adding a generator for it would make using that API much easier for them.
Thus the <code>multipart</code> generator was added to the mix.
Using it, one can make a compliant request by writing something like</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::JSON</span> &#39;<span class="hljs-string">encode_json</span>&#39;;
<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>   = &#39;<span class="hljs-string">https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart</span>&#39;;
<span class="hljs-keyword">my</span> <span class="hljs-type">$token</span> = &#39;<span class="hljs-string">XXXXXXXXXX</span>&#39;;
<span class="hljs-keyword">my</span> <span class="hljs-type">$file</span>  = <span class="hljs-function">Mojo::File</span>-&gt;new(&#39;<span class="hljs-string">local/path/to/image.jpg</span>&#39;);
<span class="hljs-keyword">my</span> <span class="hljs-type">$ua</span>    = <span class="hljs-function">Mojo::UserAgent</span>-&gt;new;

<span class="hljs-type">$ua</span>-&gt;<span class="hljs-type">post</span>(
  <span class="hljs-type">$url</span>,
  {

devdata/https_mojolicious.io_blog_2017_12_15_day-15-start-a-new-yancy-app  view on Meta::CPAN

                <!-- 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&#39;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>

devdata/https_mojolicious.io_blog_2017_12_15_day-15-start-a-new-yancy-app  view on Meta::CPAN

-- 1 down
DROP TABLE blog;
</code></pre>

<p>Next we add <a href="http://metacpan.org/pod/Mojolicious::Plugin::Yancy">the Yancy
plugin</a> and tell it
about our backend and data. Yancy deals with data as a set of
collections which contain items. For a relational database like
Postgres, a collection is a table, and an item is a row in that table.</p>

<p>Yancy uses a JSON schema to describe each item in a collection.
For our <code>blog</code> collection, we have five fields:</p>

<ol>
<li><code>id</code> which is an auto-generated integer and should be read-only</li>
<li><code>title</code> which is a free-form string which is required</li>
<li><code>created</code> which is an ISO8601 date/time string, auto-generated</li>
<li><code>markdown</code> which is a required Markdown-formatted string</li>
<li><code>html</code>, a string which holds the rendered Markdown and is also required</li>
</ol>

devdata/https_mojolicious.io_blog_2017_12_16_day-16-the-secret-life-of-sessions  view on Meta::CPAN

              </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&#39;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&#39;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>

<p>On subsequent requests, the client sends the cookie along with the request (as cookies do).
Mojolicious then checks if the document and signature validate against the secret, if so the cookie is decoded and made available again via the session method.</p>

<p>Two important things to note.
First, though the data is safe from tampering, it isn&#39;t encrypted; a savvy user can decode the cookie and see the stored data, so don&#39;t put anything in it that shouldn&#39;t be seen.
Second, this is only useful if the secret is strong and safe.
If not, the client could forge a cookie that appeared to come from your application, possibly with catastrophic results!
So while Mojolicious makes it easy, a little care can go a long way toward keeping your session data safe and trusted.</p>

devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model  view on Meta::CPAN

<p><small>lib/Wishlist/Model.pm</small></p>

<p>This class define the ways that the application can alter the data in the database.
Rather than the familiar DBI methods like <code>selectrow_arrayref</code>, Mojo-Flavored DBI make a query and then ask for the result shape they want returned.
The user can ask for a row as a hash or an array.
They can also ask for and array of all thr rows, again as a hash or an array.
Sometimes there are other data you want rather than the actual results, like the <code>last_insert_id</code> or the number of <code>rows</code> affected.</p>

<p>Most of the methods are simple enough to employ the SQL::Abstract forms: add, update, remove, even listing the users.
However for getting a user we want to make a more complex <code>query</code> by hand.
It looks up the user row by name, and aggregates the items that user is wishing for as JSON.</p>

<p>Before fetching the results we tell Mojo::SQLite that we would like to expand the JSON back into Perl data transparently.
This <a href="https://metacpan.org/pod/Mojo::SQLite::Results#expand"><code>expand</code></a> method differs slightly from the other flavors since SQLite doesn&#39;t have metadata to give Mojo::SQLite hints about which column to expand.
Once setup, when we call <code>hash</code> we get a nice Perl structure as a result.</p>

<h2>The Application Class</h2>

<p>The application class might look quite different but its behavior is very similar to yesterday.
Don&#39;t fret over every line, I will only cover the important things for our purposes.</p>

<pre><code class="hljs"><span class="hljs-keyword">package</span> Wishlist;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::Base</span> &#39;<span class="hljs-string">Mojolicious</span>&#39;;

devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api  view on Meta::CPAN

<pre><code>$ cpanm Mojolicious::Plugin::OpenAPI # server side plugin
$ cpanm OpenAPI::Client              # client to talk with the server
$ cpanm YAML::XS                     # to read YAML formatted specifications
</code></pre>

<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 &quot;seperation of concern&quot;: 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>

devdata/https_mojolicious.io_blog_2017_12_22_day-22-how-to-build-a-public-rest-api  view on Meta::CPAN

<p>Did you find OpenAPI interesting? Check out these resources to find out more:</p>

<ul>
<li><a href="https://metacpan.org/release/Mojolicious-Plugin-OpenAPI">Mojolicious::Plugin::OpenAPI</a>
contains guides and synopsis to get you started.</li>
<li><a href="https://metacpan.org/pod/OpenAPI::Client">OpenAPI::Client</a>&#39;s manual
contains more information about how the client side works.</li>
<li><a href="https://swagger.io/docs/specification/about/">Swagger&#39;s about page</a> has
information about the specification and OpenAPI.</li>
<li><a href="https://www.openapis.org/">OAI</a> is the official OpenAPI resource page.</li>
<li><a href="https://metacpan.org/pod/JSON::Validator">JSON::Validator</a> is the &quot;brain&quot;
behind both the plugin and client side in Perl. Check it out, if you&#39;re
interested in JSON-Schema.</li>
</ul>

              </section>
              <small><p><a href="https://www.pexels.com/photo/hammock-palm-trees-bungalows-bora-bora-104750">Image</a> by Chris McClave, in the Public Domain.</p>
</small>

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

devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit  view on Meta::CPAN

I&#39;ll show you them below.</p>

<p>Importantly, however, the main namepace also imports <a href="http://mojolicious.org/perldoc/Mojolicious/Lite">Mojolicious::Lite</a>.
Whether you use it or not, you have a Lite app just waiting for you!
One caveat is that this does import <code>strict</code>, so you must declare your variables unless you disable strict manually.</p>

<h3>Output and Input</h3>

<p>The first two functions we will look at are related to output.
The function <code>r</code> takes an argument and formats it with <a href="http://mojolicious.org/perldoc/Mojo/Util#dumper">Mojo::Util&#39;s wrapper</a> for <a href="https://metacpan.org/pod/Data::Dumper">Data::Dumper</a>.
Somewhat similarly the <code>j</code> function takes any Perl data structure and <a href="http://mojolicious.org/perldoc/Mojo/JSON#encode_json">return it as a JSON string</a>.</p>

<pre><code>perl -Mojo -E &#39;print r({hello =&gt; &quot;world&quot;})&#39;
perl -Mojo -E &#39;print j({hello =&gt; &quot;world&quot;})&#39;
</code></pre>

<p>The <code>j</code> function is more interesting in that if you give it a string, it will <a href="http://mojolicious.org/perldoc/Mojo/JSON#decode_json">decode it from JSON</a> and return a data structure.</p>

<pre><code>echo &#39;{&quot;hello&quot;:&quot;world&quot;}&#39; | perl -Mojo -E &#39;print j(&lt;&gt;)-&gt;{hello}&#39;
</code></pre>

<p>On their own, these aren&#39;t that interesting.
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.

devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit  view on Meta::CPAN

<p>So you can slurp an HTML file with <code>f</code>, then build DOM object with <code>x</code> and get its title</p>

<pre><code>perl -Mojo -E &#39;say x(f(shift)-&gt;slurp)-&gt;at(&quot;title&quot;)-&gt;text&#39; test.html
</code></pre>

<p>or as we did earlier, get urls from a file, but this time <code>trim</code> unslightly whitespace from the output</p>

<pre><code>perl -Mojo -nlE &#39;say b(g($_)-&gt;dom-&gt;at(&quot;title&quot;)-&gt;text)-&gt;trim&#39; sites
</code></pre>

<p>We can slurp the <code>sites</code> file itself, split the lines and ouput it as JSON.</p>

<pre><code>perl -Mojo -E &#39;print j({sites =&gt; b(f(shift)-&gt;slurp)-&gt;split(&quot;\n&quot;)})&#39; sites
</code></pre>

<p>We can even <code>trim</code> and <code>sort</code> while we do it</p>

<pre><code>perl -Mojo -E &#39;print j({sites =&gt; b(f(shift)-&gt;slurp)-&gt;split(&quot;\n&quot;)-&gt;map(&quot;trim&quot;)-&gt;sort})&#39; sites
</code></pre>

<h3>The Lite App</h3>

devdata/https_mojolicious.io_blog_2017_12_23_day-23-one-liners-for-fun-and-profit  view on Meta::CPAN

<pre><code>29.3775 wallclock secs (29.11 usr +  0.26 sys = 29.37 CPU) @  0.34/s (n=10)
</code></pre>

<p>Knowing that data taken with and without proposed changes we can have a better idea of the performance gains or impacts from that change.
While there is no magic in this function, the ease-of-use of the benchmarker means we are actually likely to use it, even for what may seem like small and insignificant changes.
This is a major reason for Mojolicious&#39; consistently blazing speeds.</p>

<h2>Conclusion</h2>

<p>Making <code>ojo</code> one-liners can be great to experiment with new concepts, demonstrate problems, fetch and work with data, and many other tasks.
You might use them in non-web one-liners that need JSON or Data::Dumper or perhaps MMojo::Collection for chaining.
(Speaking of chaining, for bonus points, check out <a href="https://metacpan.org/pod/ojoBox">ojoBox</a> for <a href="https://metacpan.org/pod/Mojo::Autobox">autoboxing Perl types</a>, making even cooler chains!)</p>

<p>These one-liners are not going to be everyone&#39;s cup of tea.
If these don&#39;t seem like your&#39;s you can completely ignore them.</p>

<p>However, once you start using them, I think you&#39;ll find yourself using them often.</p>

              </section>
              <small><p><a href="https://commons.wikimedia.org/w/index.php?curid=21375125">Image</a> by © <a href="http://www.royan.com.ar" rel="nofollow">Jorge Royan</a>, <a href="https://creativecommons.org/licenses/by-sa/3.0" title="Creative Co...
</small>

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017.pm  view on Meta::CPAN

package Acme::CPANModules::Import::MojoliciousAdvent::2017;

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/page/advent/2017/] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"App::cpanminus"},{module=>"Mojo:...

1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2017

__END__

=pod

=encoding UTF-8

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017.pm  view on Meta::CPAN

=item * L<Mojolicious::Command::inflate>

=item * L<Mojolicious::Lite>

=item * L<IO::Socket::SSL>

=item * L<Mojo::DOM>

=item * L<Mojo::DOM::CSS>

=item * L<Mojo::JSON>

=item * L<Mojo::Pg>

=item * L<Mojo::UserAgent>

=item * L<Mojolicious::Command::cgi>

=item * L<Mojolicious::Command::cpanify>

=item * L<Mojolicious::Command::daemon>

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017.pm  view on Meta::CPAN

=item * L<Mojolicious::Command::nopaste>

=item * L<Mojolicious::Commands>

=item * L<FindBin>

=item * L<Mojo::Base>

=item * L<Mojo::IOLoop>

=item * L<Mojo::JSON::Pointer>

=item * L<Mojo::UserAgent::Transactor>

=item * L<Mojolicious::Plugin::Config>

=item * L<Mojolicious::Plugin::JSONConfig>

=item * L<Test::Mojo>

=item * L<Test::Mojo::Role::Debug>

=item * L<Test::More>

=item * L<Mojolicious::Plugin::DefaultHelpers>

=item * L<Mojolicious::Plugin::ReplyTable>

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017.pm  view on Meta::CPAN

=item * L<Mock::MonkeyPatch>

=item * L<Test::Harness>

=item * L<Mojo::Asset::File>

=item * L<Mojo::IOLoop::Stream>

=item * L<Mojo::Loader>

=item * L<JSON::Validator>

=item * L<Mojolicious::Plugin::OpenAPI>

=item * L<Mojolicious::Routes::Route>

=item * L<OpenAPI::Client>

=item * L<Benchmark>

=item * L<Data::Dumper>

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_05.pm  view on Meta::CPAN

package Acme::CPANModules::Import::MojoliciousAdvent::2017_12_05;

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/05/day-5-your-apps-built-in-commands] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"...

1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2017 (day 05)

__END__

=pod

=encoding UTF-8

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_05.pm  view on Meta::CPAN

=head1 INCLUDED MODULES

=over

=item * L<IO::Socket::SSL>

=item * L<Mojo::DOM>

=item * L<Mojo::DOM::CSS>

=item * L<Mojo::JSON>

=item * L<Mojo::Pg>

=item * L<Mojo::UserAgent>

=item * L<Mojolicious::Command::cgi>

=item * L<Mojolicious::Command::cpanify>

=item * L<Mojolicious::Command::daemon>

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_09.pm  view on Meta::CPAN

package Acme::CPANModules::Import::MojoliciousAdvent::2017_12_09;

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/09/day-9-the-best-way-to-test] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"FindBin...

1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2017 (day 09)

__END__

=pod

=encoding UTF-8

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_09.pm  view on Meta::CPAN

=item * L<FindBin>

=item * L<Mojo::Base>

=item * L<Mojo::DOM>

=item * L<Mojo::DOM::CSS>

=item * L<Mojo::IOLoop>

=item * L<Mojo::JSON>

=item * L<Mojo::JSON::Pointer>

=item * L<Mojo::Transaction>

=item * L<Mojo::UserAgent>

=item * L<Mojo::UserAgent::Transactor>

=item * L<Mojolicious::Controller>

=item * L<Mojolicious::Plugin::Config>

=item * L<Mojolicious::Plugin::JSONConfig>

=item * L<Test::Mojo>

=item * L<Test::Mojo::Role::Debug>

=item * L<Test::More>

=back

=head1 HOMEPAGE

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

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_22.pm  view on Meta::CPAN

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>

=item * L<Mojolicious::Plugin::OpenAPI>

=item * L<Mojolicious::Routes::Route>

=item * L<OpenAPI::Client>

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_23.pm  view on Meta::CPAN

package Acme::CPANModules::Import::MojoliciousAdvent::2017_12_23;

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/23/day-23-one-liners-for-fun-and-profit] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module...

1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2017 (day 23)

__END__

=pod

=encoding UTF-8

lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_23.pm  view on Meta::CPAN

=item * L<Mojo::Autobox>

=item * L<Mojo::ByteStream>

=item * L<Mojo::Collection>

=item * L<Mojo::DOM>

=item * L<Mojo::File>

=item * L<Mojo::JSON>

=item * L<Mojo::Message::Response>

=item * L<Mojo::UserAgent>

=item * L<Mojo::Util>

=item * L<Mojolicious::Command::eval>

=item * L<Mojolicious::Command::get>



( run in 0.843 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )