The Mojolicious Blog.

A semi-official blog dedicated to the Mojolicious web framework

Announcing Mojolicious 9.0

Mojolicious cloud with text "nine point oh"

The Mojolicious Core Team is delighted to announce the release and immediate availability of version 9.0 of the Mojolicious real-time web framework. Every Mojolicious major release has a code name based on a unicode character and this one is lovingly named "Waffle" 🧇!

Every major release I think that there can't be much more to add or change in Mojolicious and then when the next one arrives I reflect on how much has changed since I last thought that. In 9.0 there's far too much to discuss each at length, so I'm going to highlight some of my favorites and then include a distilled list of changes since 8.0.

Perl 5.16 and beyond

Mojolicious now requires Perl version 5.16. This change gives us useful tools to build Mojolicious including the __SUB__ token for building self-referential callbacks without leaking. We were pleased that the community response since the change a few months ago has been ... well crickets. This is great news since we do hope to move to Perl 5.20 in the not so distant future so that we can use Perl's native signatures once that is a sound option for us. We are already encouraging the use of signatures both in the documentation and in our code generation commands.

Asynchronous Functionality

Clearly the highlight of the pre-9.0 development cycle has been the integration of Async/Await. Thanks to Paul Evans (LeoNerd)'s efforts, when you have Future::AsyncAwait installed Mojolicious can use its new keywords async and await to provide the most seamless asynchronous development possible, something that is becoming more and more the standard for asynchronous code in other languages. Writing a non-blocking endpoint is now as simple as

use Mojolicious::Lite -signatures, -async_await;

# Request HTML titles from two sites non-blocking
get '/' => async sub ($c) {
  my $mojo_tx    = await $c->ua->get_p('https://mojolicious.org');
  my $mojo_title = $mojo_tx->result->dom->at('title')->text;
  my $cpan_tx    = await $c->ua->get_p('https://metacpan.org');
  my $cpan_title = $cpan_tx->result->dom->at('title')->text;

  $c->render(json => {mojo => $mojo_title, cpan => $cpan_title});
};

app->start;

When I teach non-blocking to people I can now tell them to follow a trivial recipe for most non-blocking tasks. Simply await any function that returns a promise and mark any function that uses await with the async keyword. Note also that all async functions return promises so await any calls to them. There are some optimizations you can make at times and top-level await (if you aren't in a Mojolicious webapp) can be a little strange but to a first approximation that's all you need to write a non-blocking webapp today!

Speaking of promises (which are at the heart of Async/Await), Mojo::Promise has grown a lot this cycle too, adding all_settled, any, map, timer, and timeout class methods, changing its constructor to be more like the one in JavaScript and to warn when an unhandled rejected promise is destroyed. The latter can help in development where such cases used to hide errors, now, much like the browser, you can at least find where things are going wrong even if you didn't wire all your promises to a catch callback like you should.

Continue reading Announcing Mojolicious 9.0...

Day 3: Using Named Routes

"my name is" stickers

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?

Each Mojolicious route has its own name 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).

Then when you need a url, rather than hard-coding it, use url_for or related functionality to generate a url by name, you can even pass placeholder values if needed. Let's see how it works!

Continue reading Day 3: Using Named Routes...