Mojolicious is a fantastic web framework for Perl. It has a lot of Guides, so here there are some things that might come handy every now and then, from the perspective of a non-professional user.

Starter code for lite app

Starter code for Mojolicious::Lite app:

#!/usr/bin/env perl
use Mojolicious::Lite -signatures;
get '/:foo' => sub ($c) {
  my $foo = $c->param('foo');
  $c->render(text => "Hello from $foo.");
};
app->start;

Parameters Handling

Handling parameters (in a controller sub, $c is the controller object):

# Get/Set
my $foo = $c->param('foo')
$c->param(foo => 'whatever');

A parameter might appear multiple times, use every_param to get all values out as a list

# Multiple values for the same parameter
my @foo = $c->every_param('foo');

It’s possible to get all params at once as a hash reference passing through the request object:

my $all_params_hash = $c->req->params;          # All params

The same req object can also provide parameters back based on where they came from:

my $foo = $c->req->query_params->param('foo');  # GET
my $foo = $c->req->body_params->param('foo');   # POST
my $foo = $c->req->param('foo');                # GET & POST
my $foo = $c->req->upload('foo');               # file uploads

Generating a Response

Look at the main guide on Rendering too!

It’s possible to declare what kind of data we are returning and trigger automated behaviours:

$c->render(text => "OK\n");        # characters
$c->render(json => {});            # JSON encoding & application/json
$c->render(data => $bytes);        # bytes
$c->render(template => 'index');   # generated by Mojolicious tooling

When setting bytes with data, also make sure to set the right Content-Type with keyword format or explicitly, like this:

$c->res->headers->content_type('application/octet-stream');

HTTP status code

Use the status named option when calling render:

$c->render(text => "OK\n", status => 201);

Content-Type

There are some pre-defined MIME types that can be used to set the Content-Type automatically using named option format in render:

$c->render(data => $octets, format => 'png');  # image/png

Setting specific aliases is easy:

# most probably at application setup
...
$app->types->type(foo => 'application/octet-stream');
...

# later, in a controller $c...
...
$c->render(data => $octets, format => 'foo');  # application/octet-stream
...

Otherwise, it’s possible to operate at a lower level, setting the Content-Type directly in the response headers in the controller:

$c->res->headers->content_type('application/octet-stream');
# OR: $c->res->headers->header('Content-Type', 'application/octet-stream');

No Content

When the answer is successful but nothing should be sent back in the body:

$c->rendered(204);

This both sets the status code and the Content-Type.

Custom headers

The res method in a controller gives access to the Mojo::Message::Response object, for fine-grained control over headers.

# in a controller $c
my $headers = $c->res->headers;

$headers->cache_control('public, max-age=300');
$headers->www_authenticate('Basic realm="whatever"');

There is also a generic method to set custom headers:

$headers->header('X-foo' => 'bar');
$headers->header('X-baz' => [qw< baz1 baz2 baz3 >]);

Force download with specific filename

Sometimes you would like to ease the client’s anticipated need to save a content instead of looking at it in the browser:

my $filename = 'bar.pdf';
$c->res->headers->content_disposition('attachment; filename=$filename;');
$c->render(data => $datastring, format => 'pdf')

Embedded Perl

Mojolicious supports dynamic generation of content using Embedded Perl (example below copied from documentation):

<% Perl code %>
<%= Perl expression, replaced with XML escaped result %>
<%== Perl expression, replaced with result %>
<%# Comment, useful for debugging %>
<%% Replaced with "<%", useful for generating templates %>
% Perl code line, treated as "<% line =%>" (explained later)
%= Perl expression line, treated as "<%= line %>"
%== Perl expression line, treated as "<%== line %>"
%# Comment line, useful for debugging
%% Replaced with "%", useful for generating templates

HTML generation shortcuts are provided by TagHelpers:

%= text_field 'first_name'
%= text_field first_name => 'Default'
%= text_field first_name => 'Default', class => 'user'
%= hidden_field foo => 'bar'
%= hidden_field foo => 'bar', id => 'bar'
%= submit_button
%= submit_button 'Ok!', id => 'foo'

Stash

The stash is a handy way of passing data down to a renderer, e.g. an Embedded Perl template.

One big caveat is that it shares the same namespace as some of the facilities that method render offers by itself, e.g. json for automatic JSON encoding and Content-Type setting, or status, etc.

As of Mojolicious 9.33, the docs for stash report that the following keys have a special meaning and would collide with any variable one might be tempted to set:

  • action: allows defining a method to call inside a controller class for routing a request. See Special stash values.
  • app: I don’t know!
  • cb: set a callback function that is called like a controller method, but it’s not a method of the controller. See Route to callback.
  • controller: allows defining the controller class for routing a request. See Special stash values.
  • data: sets the content of the response with raw data bytes. See Rendering data.
  • extends: basic mechanism to support Template inheritance. This keyword’s value is set to make a template inherit from another one.
  • format: drives setting the Content-Type using known MIME type mappings. See Content type.
  • handler: select the templating system for expanding templates. See Rendering.
  • inline: renders an inline template, i.e. passed as a simple string. See Rendering inline templates.
  • json: sets the content of the response by encoding a data structure to JSON and the Content-Type to application/json. See Rendering JSON.
  • layout: selects the layout for rendering. See Layouts.
  • namespace: set the basic prefix for generating controller class names. See Namespaces.
  • path: I don’t know!
  • status: sets the HTTP status code of the response. See Status code.
  • template: selects the template for rendering.
  • text: sets the content of the response to a text and the Content-Type as a variant of text/plain according to the encoding. See Rendering text.
  • variant: choose a variant of a template. See Template variants.
  • mojo.*: this whole sub-namespace is reserved for internal use.

The docs also make it clear that this is the current list, which might mean it might change in the future (e.g. more keys might be reserved), which might mean that using the stash might be a risk for upgrading. If this does not get updates, there is a discussion about it.

CORS - Cross-Origin Resource Sharing

See CORS, suppose we have a user browsing pages at visible-to-user.com, whose pages include Javascript that try to access endpoints in behind-the-courtains.org:

# handle CORS from the server side, i.e. in behind.the-courtains.org
options '/path/to/resource' => sub ($c) {
    $c->res->headers->header(
        'Access-Control-Allow-Origin' => 'visible.to-user.com');
    $c->render(code => 204);
};
post '/path/to/resource' => sub ($c) {
    $c->res->headers->header(
        'Access-Control-Allow-Origin' => 'visible.to-user.com');
    return $c->render(json => {everything => 'OK'});
};

Authentication

See specific page.

Logging

The main application exposes a method log that gives access to the Mojo::Log object:

app->log->info('this is from where the main app is visible');

get '/in/controller' => sub ($c) {
    $c->app->log->info('this is from a controller');
}

Supported Levels

From the SYNOPSIS of Mojo::Log, the following log levels are supported:

# Log messages
$log->trace('Doing stuff');
$log->debug('Not sure what is happening here');
$log->info('FYI: it happened again');
$log->warn('This might be a problem');
$log->error('Garden variety error');
$log->fatal('Boom');

Log::Any as a backend

It’s possible to pass all logs over to Log::Any, so that logging from the Mojolicious application and other modules using Log::Any can all share a single logging channel. The plugin is Mojolicious::Plugin::Log::Any.

In a Mojolicious::Lite app:

use Mojolicious::Lite;
use Log::Any::Adapter ...; # whatever adapter is needed!
plugin 'Log::Any';

In a more structured application:

package SomeApp;
use Mojo::Base Mojolicious => -signatures;
use Log::Any::Adapter ...; # whatever adapter is needed!

sub start ($self) {
    $self->plugin('Log::Any');
}

1;

Log::Any as a frontend

It’s possible to make Mojo::Log a backend for Log::Any-enabled code using Log::Any::Adapter::MojoLog. Thia allows channeling all logs through Mojolicious.

In a Mojolicious::Lite app:

use Mojolicious::Lite;
use Log::Any::Adapter;
Log::Any::Adapter->set(MojoLog => logger => app->log);

In a more structured application:

package SomeApp;
use Mojo::Base Mojolicious => -signatures;
use Log::Any::Adapter;

sub start ($self) {
    Log::Any::Adapter->set(MojoLog => logger => $self->log);
}

1;

Logging static requests

Requests that are mapped onto static content are not logged by default. Plugin Mojolicious::Plugin::StaticLog can help with this.

Mojolicious::Lite:

use Mojolicious::Lite;
plugin 'StaticLog';  # log level defaults to debug
# plugin StaticLog => { level => 'info' }; # fine-grained control

In a more structured application:

package SomeApp;
use Mojo::Base Mojolicious => -signatures;
use Log::Any::Adapter;

sub start ($self) {
    $self->plugin( StaticLog => {level=>'info'} );
}

1;

See Also

Also: