view release on metacpan or search on metacpan
"Carton" : "0",
"Coro" : "0",
"Crypt::Eksblowfish::Bcrypt" : "0",
"DBI" : "0",
"Dancer" : "0",
"Dancer2" : "0",
"Dancer2::Plugin::WebSocket" : "0",
"Dancer2::Template::Simple" : "0",
"File::Find" : "0",
"HTML::WikiConverter" : "0",
"JSON::Validator" : "0",
"Minion" : "0",
"Minion::Backend::SQLite" : "0",
"Minion::Command::minion::job" : "0",
"Minion::Command::minion::worker" : "0",
"Mojo::AsyncAwait" : "0",
"Mojo::Base" : "0",
"Mojo::Collection" : "0",
"Mojo::DOM" : "0",
"Mojo::DOM::CSS" : "0",
"Mojo::File" : "0",
"Mojo::Headers" : "0",
"Mojo::HelloWorld" : "0",
"Mojo::JSON::Pointer" : "0",
"Mojo::Message::Request" : "0",
"Mojo::Message::Response" : "0",
"Mojo::Pg" : "0",
"Mojo::Promise" : "0",
"Mojo::Promise::Role::HigherOrder" : "0",
"Mojo::SQLite" : "0",
"Mojo::SQLite::Migrations" : "0",
"Mojo::Server::Hypnotoad" : "0",
"Mojo::Server::PSGI" : "0",
"Mojo::Template" : "0",
"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",
],
"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
}
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_2018_12_07_openapi_ view on Meta::CPAN
<p>ReDoc creates an interactive page providing documentation and examples based on the details provided in the OpenAPI specification file. ReDoc includes a <a href="https://github.com/Rebilly/ReDoc#tldr">HTML template</a> to be served as a static fil...
<ul>
<li><a href="https://metacpan.org/pod/Mojolicious::Plugin::OpenAPI">Mojolicious::Plugin::OpenAPI</a> â OpenAPI / Swagger plugin for Mojolicious</li>
</ul>
<p>Reads the OpenAPI specification file and adds the appropriate routes and validations for your Mojolicious based application.</p>
<ul>
<li><a href="https://metacpan.org/pod/JSON::Validator">JSON::Validator</a> â Validate data against a JSON schema</li>
</ul>
<p>Integrated into the Mojolicious::Plugin::OpenAPI module, provides the input and output validation, as well as providing validation for the specification file itself.</p>
<h2>Getting Started</h2>
<p>The following strategy was used when implementing the MetaCPAN OpenAPI specification.</p>
<h3>The OpenAPI Specification File</h3>
<p>With support for multiline attribute values making it much easier to read and write with less formatting, we chose YAML. JSON is also supported.</p>
<pre><code># Define the version of the OpenAPI spec to use. Version 2.0 still uses
# swagger as the key
swagger: "2.0"
# general information about the API
info:
version: "1.0.0"
title: "MetaCPAN API"
# common path shared throughout the API
basePath: "/v1"
devdata/https_mojolicious.io_blog_2018_12_07_openapi_ view on Meta::CPAN
items:
# While items can be further broken into properties per item,
# type `object` is a catch all
type: object
</code></pre>
<h3>Advanced Definitions</h3>
<h4>Reusing definitions through references</h4>
<p>The specification allows for reuse by means of <a href="https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03">JSON references</a>. The <code>$ref</code> attribute is a relative pointer to the file and section (again separated by <code>#</code>...
<pre><code> results:
title: Results
type: array
items:
$ref: "../definitions/results.yml#/search_result_items"
</code></pre>
<p>The v2.0 specification does have restrictions on where references can be use, which does cause repetition in the specification file. The v3.0 specification has corrected these issues, and also allows for <code>http</code> references.</p>
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_ view on Meta::CPAN
of jobs in the given state, any locks that exist, and the workers.</p>
<p><img alt="A web browser showing a list of jobs in the "finished"
state" src="02-job-list.png"></p>
<p>When looking at a list of jobs, I can click the buttons on top left to
manage the job queue, or click on the caret on the right of each job row
to view the details of that job (the same as the <code>job</code> command shows).</p>
<p><img alt="A web browser showing the details of a single Minion job as
JSON" src="03-job-details.png"></p>
<p>The Minion Admin UI is a great addition to a great tool! <a href="minion.pl">View the entire
source of the Minion app</a></p>
</section>
<small><p>Original artwork by Doug Bell, released under CC-BY-SA 4.0. It includes
the Minion logo (CC-BY-SA 4.0)</p>
</small>
<p class="tags">
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
Mojolicious.
I've been 'round the houses, and <em>spoiler alert</em> I didn't find
the answer until the very end, kind of like your favourite Christmas
animated special with a small woodland creature narrating
"The Gruffalo's HTTP header".</p>
<h1>A Children's Story</h1>
<p>Our beloved small woodland creature needed to display a web calendar
with forest events pulled from a database.
Perl could get the event data and package it as a JSON feed.
Mojolicious could prepare the webpages with the correct JSON feed for each user.
With some JavaScript libraries to display the web calendar,
all would be well in the forest.</p>
<p>Everything except the JavaScript libraries are lightweight.
And everyone knows a page reload goes <em>so</em> much faster if it doesn't have to download the
JavaScript every time. Those libraries won't change for months!
If only the client browser knew that it could use the file that it had downloaded
last time.</p>
<p>The secret, of course, is to set the <code>Cache-Control</code> field of the HTTP header, but <em>how</em>?</p>
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
my $class = Test::Mojo->with_roles('+PSGI');
</code></pre>
<p>Then you instantiate that role with the path to the PSGI application, or else the PSGI application itself.</p>
<p>Since you're using roles, which are all about composition, you can also apply other roles that you might <a href="https://metacpan.org/search?q=%22Test%3A%3AMojo%3A%3ARole%22">find on CPAN</a>.</p>
<h2>An Example</h2>
<p>As an example, let's say we have a simple application script (named <code>app.psgi</code>) that can render a <code>"hello world"</code> or <code>"hello $user"</code> in several formats.
I'll allow a plain text response, JSON, and templated HTML (using the <a href="https://metacpan.org/pod/Dancer2::Template::Simple">simple</a> template to keep this concise).</p>
<pre><code>use Dancer2;
set template => 'simple';
set views => '.';
any '/text' => sub {
my $name = param('name') // 'world';
send_as plain => "hello $name";
};
any '/data' => sub {
my $name = param('name') // 'world';
send_as JSON => { hello => $name };
};
any '/html' => sub {
my $name = param('name') // 'world';
template 'hello' => { name => $name };
};
start;
</code></pre>
<p>And the template (<code>hello.tt</code>) is</p>
<pre><code><dl id="data">
<dt id="hello">hello</dt>
<dd><% name %></dd>
</dl>
</code></pre>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl">dl</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt">dt</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd">dd</a> tags...
The HTML I've built, while nice for display isn't necessarily nice for querying programmatically, this is on purpose for the example.</p>
<h2>The Tests</h2>
<p>Of course we could start the application with <a href="https://metacpan.org/pod/distribution/Plack/script/plackup"><code>plackup</code></a> but that's not what we're trying to do.
I'll break the test script down a bit but if you want to see any of these files look at the <a href="https://github.com/MojoliciousDotIO/mojolicious.io/tree/master/blog/2018/12/20/testing-dancer/ex">blog repo</a> for a full listing.
Instead, let's load this into a test script.</p>
<pre><code>use Mojo::Base -strict;
</code></pre>
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
->json_is('/hello' => 'world');
$t->post_ok('/data' => form => { name => 'rudolph' })
->status_is(200)
->content_type_like(qr[application/json])
->json_is('/hello' => 'rudolph');
</code></pre>
<p>You can see we use the <code>json_is</code> method to test the responses.
Now, the test could have been <code>->json_is({hello => 'rudolph'})</code> if had wanted to test the entire document.
By passing a <a href="https://mojolicious.org/perldoc/Mojo/JSON/Pointer">JSON Pointer</a> I can inspect only the portions I'm interested in.</p>
<p>Finally I'm going to test the HTML endpoint.
As I said above, the result resists easy parsing.
We want to test the <code>dd</code> tag contents that follows a <code>dt</code> tag with the id <code>hello</code>, all inside a <code>dl</code> tag with the id <code>data</code>.
That would be a monstrous regexp (hehe).
However it is a piece of cake using <a href="https://mojolicious.org/perldoc/Mojo/DOM/CSS">CSS Selectors</a>.</p>
<pre><code>$t->get_ok('/html')
->status_is(200)
->content_type_like(qr[text/html])
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
$t->websocket_ok($url)
->send_ok({json => {hello => 'Dancer'}})
->message_ok
->json_message_is({hello => 'browser!'})
->finish_ok;
done_testing;
</code></pre>
<p>Unlike the previous examples, this time the connection stays open (but blocked) between method calls.
Per the protocol of the example, we first send a greeting to the Dancer app as a JSON document.
Since so much real-world websocket usage is just serialized JSON messages, Mojolicious provides many JSON-over-WebSocket conveniences.
One such convenience is a virtual websocket frame type that takes a data structure and serializes it as JSON before actually sending it as a text frame.</p>
<p>We then wait to get a message in response with <code>message_ok</code>.
In this case, we expect the application to greet us by calling us "browser!".
Oh well, it doesn't know any better!
We can the test that JSON reply with <code>json_message_is</code> (like <code>json_is</code> above but for websocket messages).
Finally we close the connection, testing that it closes correctly.</p>
<p>Testing WebSockets, even from a Dancer application, is easy!</p>
<h2>Conclusion</h2>
<p>Although there are some great testing options in the PSGI space, Test::Mojo has lots of benefits for Dancer and PSGI users.
By using <code>Test::Mojo::Role::PSGI</code> or by running against a locally-bound server, Test::Mojo can be a tool in the toolbox of any PSGI developer.</p>
</section>
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
));
main(@urls)->wait;
</code></pre>
<p>Were this code written sequentially, the time it would take to run would be the sum of the time to fetch each url.
However, as written, this will run in approximately the time it takes for the slowest url to respond.</p>
<h3>Web Apps</h3>
<p>Now let's say you wanted to turn that script into a web API.
If we had a webapp that accepted urls as query parameters and returned the responses as JSON it might look like this</p>
<pre><code>use Mojolicious::Lite -signatures;
use Mojo::AsyncAwait;
use Mojo::Promise;
use Mojo::Util 'trim';
plugin 'PromiseActions';
helper get_title_p => async sub ($c, $url) {
my $tx = await $c->ua->get_p($url);
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2018;
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/] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"Mojolicious::Plugin::AutoReload"},{module=>"Mojo:...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2018
__END__
=pod
=encoding UTF-8
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018.pm view on Meta::CPAN
=item * L<Mojo::SQLite>
=item * L<Mojo::SQLite::Migrations>
=item * L<Mojolicious::Plugin::TagHelpers>
=item * L<Yancy>
=item * L<Yancy::Controller::Yancy>
=item * L<JSON::Validator>
=item * L<Mojolicious::Plugin::OpenAPI>
=item * L<Crypt::Eksblowfish::Bcrypt>
=item * L<DBI>
=item * L<MojoX::Auth::Simple>
=item * L<MojoX::Session>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018.pm view on Meta::CPAN
=item * L<Mojolicious::Plugin::PODRenderer>
=item * L<Mojolicious::Plugin::PODViewer>
=item * L<Mojolicious::Command::export>
=item * L<Dancer2::Plugin::WebSocket>
=item * L<Dancer2::Template::Simple>
=item * L<Mojo::JSON::Pointer>
=item * L<Mojo::Server::PSGI>
=item * L<Mojolicious::Plugin::Mount>
=item * L<Mojolicious::Plugin::MountPSGI>
=item * L<PSGI>
=item * L<Plack::Test>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_07.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2018_12_07;
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/2018/12/07/openapi/] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"JSON::Validator"},{module...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2018 (day 07)
__END__
=pod
=encoding UTF-8
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_07.pm view on Meta::CPAN
This module is generated by extracting module names mentioned in L<https://mojolicious.io/blog/2018/12/07/openapi/> (retrieved on 2018-12-30). Visit the URL for the full contents.
Modules mentioned in Mojolicious Advent Calendar 2018 (day 07).
This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2018/12/07/openapi/] (retrieved on 2018-12-30). Visit the URL for the full contents.
=head1 INCLUDED MODULES
=over
=item * L<JSON::Validator>
=item * L<Mojolicious::Plugin::OpenAPI>
=back
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2018>.
=head1 SOURCE
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_20.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2018_12_20;
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/2018/12/20/testing-dancer/] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"Dancer2::Plugin::W...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2018 (day 20)
__END__
=pod
=encoding UTF-8
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_20.pm view on Meta::CPAN
=head1 INCLUDED MODULES
=over
=item * L<Dancer2::Plugin::WebSocket>
=item * L<Dancer2::Template::Simple>
=item * L<Mojo::DOM::CSS>
=item * L<Mojo::JSON::Pointer>
=item * L<Mojo::Server::PSGI>
=item * L<Mojo::UserAgent>
=item * L<Mojolicious::Plugin::Mount>
=item * L<Mojolicious::Plugin::MountPSGI>
=item * L<PSGI>