The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Mojolicious::Lite - Real-time micro web framework

SYNOPSIS

# Automatically enables "strict", "warnings" and Perl 5.10 features
use Mojolicious::Lite;

# Route with placeholder
get '/:foo' => sub {
  my $self = shift;
  my $foo  = $self->param('foo');
  $self->render(text => "Hello from $foo.");
};

# Start the Mojolicious command system
app->start;

DESCRIPTION

Mojolicious::Lite is a micro real-time web framework built around Mojolicious.

TUTORIAL

A quick example driven introduction to the wonders of Mojolicious::Lite. Most of what you'll learn here also applies to normal Mojolicious applications.

Hello World

A simple Hello World application can look like this, strict, warnings and Perl 5.10 features are automatically enabled and a few functions imported when you use Mojolicious::Lite, turning your script into a full featured web application.

#!/usr/bin/env perl
use Mojolicious::Lite;

get '/' => sub {
  my $self = shift;
  $self->render(text => 'Hello World!');
};

app->start;

Generator

There is also a helper command to generate a small example application.

$ mojo generate lite_app

Commands

All the normal Mojolicious::Commands are available from the command line. Note that CGI and PSGI environments can usually be auto detected and will just work without commands.

$ ./myapp.pl daemon
Server available at http://127.0.0.1:3000.

$ ./myapp.pl daemon -l http://*:8080
Server available at http://127.0.0.1:8080.

$ ./myapp.pl cgi
...CGI output...

$ ./myapp.pl
...List of available commands (or automatically detected environment)...

Start

The app->start call that starts the Mojolicious command system can be customized to override normal @ARGV use.

app->start('cgi');

Reloading

Your application will automatically reload itself if you start it with the morbo development web server, so you don't have to restart the server after every change.

$ morbo myapp.pl
Server available at http://127.0.0.1:3000.

Routes

Routes are basically just fancy paths that can contain different kinds of placeholders. $self is a Mojolicious::Controller object containing both, the HTTP request and response.

# /foo
get '/foo' => sub {
  my $self = shift;
  $self->render(text => 'Hello World!');
};

GET/POST parameters

All GET and POST parameters are accessible via "param" in Mojolicious::Controller.

# /foo?user=sri
get '/foo' => sub {
  my $self = shift;
  my $user = $self->param('user');
  $self->render(text => "Hello $user.");
};

Stash and templates

The "stash" in Mojolicious::Controller is used to pass data to templates, which can be inlined in the DATA section.

# /bar
get '/bar' => sub {
  my $self = shift;
  $self->stash(one => 23);
  $self->render('baz', two => 24);
};

__DATA__

@@ baz.html.ep
The magic numbers are <%= $one %> and <%= $two %>.

For more information about templates see also "Embedded Perl" in Mojolicious::Guides::Rendering.

HTTP

"req" in Mojolicious::Controller and "res" in Mojolicious::Controller give you full access to all HTTP features and information.

# /agent
get '/agent' => sub {
  my $self = shift;
  $self->res->headers->header('X-Bender' => 'Bite my shiny metal ass!');
  $self->render(text => $self->req->headers->user_agent);
};

Route names

All routes can have a name associated with them, this allows automatic template detection and back referencing with "url_for" in Mojolicious::Controller as well as many helpers like "link_to" in Mojolicious::Plugin::TagHelpers. Nameless routes get an automatically generated one assigned that is simply equal to the route itself without non-word characters.

# /
get '/' => sub {
  my $self = shift;
  $self->render;
} => 'index';

# /hello
get '/hello';

__DATA__

@@ index.html.ep
<%= link_to Hello  => 'hello' %>.
<%= link_to Reload => 'index' %>.

@@ hello.html.ep
Hello World!

Layouts

Templates can have layouts too, you just select one with the helper "layout" in Mojolicious::Plugin::DefaultHelpers and place the result of the current template with the helper "content" in Mojolicious::Plugin::DefaultHelpers.

# /with_layout
get '/with_layout' => sub {
  my $self = shift;
  $self->render('with_layout');
};

__DATA__

@@ with_layout.html.ep
% title 'Green';
% layout 'green';
Hello World!

@@ layouts/green.html.ep
<!DOCTYPE html>
<html>
  <head><title><%= title %></title></head>
  <body><%= content %></body>
</html>

Blocks

Template blocks can be used like normal Perl functions and are always delimited by the begin and end keywords.

# /with_block
get '/with_block' => 'block';

__DATA__

@@ block.html.ep
% my $link = begin
  % my ($url, $name) = @_;
  Try <%= link_to $url => begin %><%= $name %><% end %>.
% end
<!DOCTYPE html>
<html>
  <head><title>Sebastians frameworks</title></head>
  <body>
    %= $link->('http://mojolicio.us', 'Mojolicious')
    %= $link->('http://catalystframework.org', 'Catalyst')
  </body>
</html>

Captured content

The helper "content_for" in Mojolicious::Plugin::TagHelpers can be used to pass around blocks of captured content.

# /captured
get '/captured' => sub {
  my $self = shift;
  $self->render('captured');
};

__DATA__

@@ captured.html.ep
% layout 'blue', title => 'Green';
% content_for header => begin
  <meta http-equiv="Pragma" content="no-cache">
% end
Hello World!
% content_for header => begin
  <meta http-equiv="Expires" content="-1">
% end

@@ layouts/blue.html.ep
<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    %= content_for 'header'
  </head>
  <body><%= content %></body>
</html>

Helpers

You can also extend Mojolicious with your own helpers, a list of all built-in ones can be found in Mojolicious::Plugin::DefaultHelpers and Mojolicious::Plugin::TagHelpers.

# "whois" helper
helper whois => sub {
  my $self  = shift;
  my $agent = $self->req->headers->user_agent || 'Anonymous';
  my $ip    = $self->tx->remote_address;
  return "$agent ($ip)";
};

# /secret
get '/secret' => sub {
  my $self = shift;
  my $user = $self->whois;
  $self->app->log->debug("Request from $user.");
};

__DATA__

@@ secret.html.ep
We know who you are <%= whois %>.

Placeholders

Route placeholders allow capturing parts of a request path until a / or . separator occurs, results are accessible via "stash" in Mojolicious::Controller and "param" in Mojolicious::Controller.

# /foo/test
# /foo/test123
get '/foo/:bar' => sub {
  my $self = shift;
  my $bar  = $self->stash('bar');
  $self->render(text => "Our :bar placeholder matched $bar");
};

# /testsomething/foo
# /test123something/foo
get '/(:bar)something/foo' => sub {
  my $self = shift;
  my $bar  = $self->param('bar');
  $self->render(text => "Our :bar placeholder matched $bar");
};

Wildcard placeholders

Wildcard placeholders allow matching absolutely everything, including / and ..

# /hello/test
# /hello/test123
# /hello/test.123/test/123
get '/hello/*you' => 'groovy';

__DATA__

@@ groovy.html.ep
Your name is <%= $you %>.

HTTP methods

Routes can be restricted to specific request methods.

# GET /hello
get '/hello' => sub {
  my $self = shift;
  $self->render(text => 'Hello World!');
};

# PUT /hello
put '/hello' => sub {
  my $self = shift;
  my $size = length $self->req->body;
  $self->render(text => "You uploaded $size bytes to /hello.");
};

# GET|POST|PATCH /bye
any ['GET', 'POST', 'PATCH'] => '/bye' => sub {
  my $self = shift;
  $self->render(text => 'Bye World!');
};

# * /whatever
any '/whatever' => sub {
  my $self   = shift;
  my $method = $self->req->method;
  $self->render(text => "You called /whatever with $method.");
};

Optional placeholders

Routes allow default values to make placeholders optional.

# /hello
# /hello/Sara
get '/hello/:name' => {name => 'Sebastian'} => sub {
  my $self = shift;
  $self->render('groovy', format => 'txt');
};

__DATA__

@@ groovy.txt.ep
My name is <%= $name %>.

Restrictive placeholders

The easiest way to make placeholders more restrictive are alternatives, you just make a list of possible values.

# /test
# /123
any '/:foo' => [foo => ['test', 123]] => sub {
  my $self = shift;
  my $foo  = $self->param('foo');
  $self->render(text => "Our :foo placeholder matched $foo");
};

All placeholders get compiled to a regex internally, this process can also be easily customized.

# /1
# /123
any '/:bar' => [bar => qr/\d+/] => sub {
  my $self = shift;
  my $bar  = $self->param('bar');
  $self->render(text => "Our :bar placeholder matched $bar");
};

Just make sure not to use ^ and $ or capturing groups (...), because placeholders become part of a larger regular expression internally, (?:...) is fine though.

Formats

Formats can be automatically detected by looking at file extensions.

# /detection.html
# /detection.txt
get '/detection' => sub {
  my $self = shift;
  $self->render('detected');
};

__DATA__

@@ detected.html.ep
<!DOCTYPE html>
<html>
  <head><title>Detected</title></head>
  <body>HTML was detected.</body>
</html>

@@ detected.txt.ep
TXT was detected.

Restrictive placeholders can also be used for format detection.

# /hello.json
# /hello.txt
get '/hello' => [format => ['json', 'txt']] => sub {
  my $self = shift;
  return $self->render_json({hello => 'world'})
    if $self->stash('format') eq 'json';
  $self->render_text('hello world');
};

Content negotiation

For resources with different representations and that require truly RESTful content negotiation you can also use "respond_to" in Mojolicious::Controller.

# /hello (Accept: application/json)
# /hello (Accept: text/xml)
# /hello.json
# /hello.xml
# /hello?format=json
# /hello?format=xml
get '/hello' => sub {
  my $self = shift;
  $self->respond_to(
    json => {json => {hello => 'world'}},
    xml  => {text => '<hello>world</hello>'},
    any  => {data => '', status => 204}
  );
};

MIME type mappings can be extended or changed easily with "types" in Mojolicious.

app->types->type(rdf => 'application/rdf+xml');

Under

Authentication and code shared between multiple routes can be realized easily with the under statement. All following routes are only evaluated if the under callback returned a true value.

use Mojolicious::Lite;

# Authenticate based on name parameter
under sub {
  my $self = shift;

  # Authenticated
  my $name = $self->param('name') || '';
  return 1 if $name eq 'Bender';

  # Not authenticated
  $self->render('denied');
  return;
};

# / (with authentication)
get '/' => 'index';

app->start;
__DATA__;

@@ denied.html.ep
You are not Bender, permission denied.

@@ index.html.ep
Hi Bender.

Prefixing multiple routes is another good use for under.

use Mojolicious::Lite;

# /foo
under '/foo';

# /foo/bar
get '/bar' => {text => 'foo bar'};

# /foo/baz
get '/baz' => {text => 'foo baz'};

# /
under '/' => {message => 'whatever'};

# /bar
get '/bar' => {inline => '<%= $message %> works'};

app->start;

You can also group related routes, which allows nesting of multiple under statements.

use Mojolicious::Lite;

# Global logic shared by all routes
under sub {
  my $self = shift;
  return 1 if $self->req->headers->header('X-Bender');
  $self->render(text => "You're not Bender.");
  return;
};

# Admin section
group {

  # Local logic shared only by routes in this group
  under '/admin' => sub {
    my $self = shift;
    return 1 if $self->req->heaers->header('X-Awesome');
    $self->render(text => "You're not awesome enough.");
    return;
  };

  # GET /admin/dashboard
  get '/dashboard' => {text => 'Nothing to see here yet.'};
};

# GET /welcome
get '/welcome' => {text => 'Hi Bender.'};

app->start;

Conditions

Conditions such as agent and host from Mojolicious::Plugin::HeaderCondition allow even more powerful route constructs.

# /foo (Firefox)
get '/foo' => (agent => qr/Firefox/) => sub {
  my $self = shift;
  $self->render(text => 'Congratulations, you are using a cool browser.');
};

# /foo (Internet Explorer)
get '/foo' => (agent => qr/Internet Explorer/) => sub {
  my $self = shift;
  $self->render(text => 'Dude, you really need to upgrade to Firefox.');
};

# http://mojolicio.us/bar
get '/bar' => (host => 'mojolicio.us') => sub {
  my $self = shift;
  $self->render(text => 'Hello Mojolicious.');
};

Sessions

Signed cookie based sessions just work out of the box as soon as you start using them through the helper "session" in Mojolicious::Plugin::DefaultHelpers.

use Mojolicious::Lite;

get '/counter' => sub {
  my $self = shift;
  $self->session->{counter}++;
};

app->start;
__DATA__

@@ counter.html.ep
Counter: <%= session 'counter' %>

Secret

Note that you should use a custom "secret" in Mojolicious to make signed cookies really secure.

app->secret('My secret passphrase here');

File uploads

All files uploaded via multipart/form-data request are automatically available as Mojo::Upload objects. And you don't have to worry about memory usage, because all files above 250KB will be automatically streamed into a temporary file.

use Mojolicious::Lite;

# Upload form in DATA section
get '/' => 'form';

# Multipart upload handler
post '/upload' => sub {
  my $self = shift;

  # Check file size
  return $self->render(text => 'File is too big.', status => 200)
    if $self->req->is_limit_exceeded;

  # Process uploaded file
  return $self->redirect_to('form')
    unless my $example = $self->param('example');
  my $size = $example->size;
  my $name = $example->filename;
  $self->render(text => "Thanks for uploading $size byte file $name.");
};

app->start;
__DATA__

@@ form.html.ep
<!DOCTYPE html>
<html>
  <head><title>Upload</title></head>
  <body>
    %= form_for upload => (enctype => 'multipart/form-data') => begin
      %= file_field 'example'
      %= submit_button 'Upload'
    % end
  </body>
</html>

To protect you from excessively large files there is also a limit of 5MB by default, which you can tweak with the MOJO_MAX_MESSAGE_SIZE environment variable.

# Increase limit to 1GB
$ENV{MOJO_MAX_MESSAGE_SIZE} = 1073741824;

User agent

With "ua" in Mojolicious::Controller there's a full featured HTTP 1.1 and WebSocket user agent built right in. Especially in combination with Mojo::JSON and Mojo::DOM this can be a very powerful tool.

get '/test' => sub {
  my $self = shift;
  $self->render(data => $self->ua->get('http://mojolicio.us')->res->body);
};

WebSockets

WebSocket applications have never been this easy before.

websocket '/echo' => sub {
  my $self = shift;
  $self->on(message => sub {
    my ($self, $message) = @_;
    $self->send("echo: $message");
  });
};

The event "message" in Mojo::Transaction::WebSocket, which you can subscribe to with "on" in Mojolicious::Controller, will be emitted for every new WebSocket message that is received.

External templates

External templates will be searched by the renderer in a templates directory.

# /external
any '/external' => sub {
  my $self = shift;

  # templates/foo/bar.html.ep
  $self->render('foo/bar');
};

Static files

Static files will be automatically served from the DATA section (even Base64 encoded) or a public directory if it exists.

@@ something.js
alert('hello!');

@@ test.txt (base64)
dGVzdCAxMjMKbGFsYWxh

$ mkdir public
$ mv something.js public/something.js

Testing

Testing your application is as easy as creating a t directory and filling it with normal Perl unit tests.

use Test::More tests => 3;
use Test::Mojo;

use FindBin;
require "$FindBin::Bin/../myapp.pl";

my $t = Test::Mojo->new;
$t->get_ok('/')->status_is(200)->content_like(qr/Funky/);

Run all unit tests with the test command.

$ ./myapp.pl test

To make your tests more noisy and show you all log messages you can also change the application log level directly in your test files.

$t->app->log->level('debug');

Mode

To disable debug messages later in a production setup you can change the Mojolicious mode, default will be development.

$ ./myapp.pl -m production

Logging

Mojo::Log messages will be automatically written to STDERR or a log/$mode.log file if a log directory exists.

$ mkdir log

For more control the Mojolicious object can be accessed directly.

app->log->level('error');
app->routes->route('/foo/:bar')->via('GET')->to(cb => sub {
  my $self = shift;
  $self->app->log->debug('Got a request for "Hello Mojo!".');
  $self->render(text => 'Hello Mojo!');
});

More

You can continue with Mojolicious::Guides now, and don't forget to have fun!

FUNCTIONS

Mojolicious::Lite implements the following functions.

any

my $route = any '/:foo' => sub {...};
my $route = any ['GET', 'POST'] => '/:foo' => sub {...};

Generate route with "any" in Mojolicious::Routes::Route, matching any of the listed HTTP request methods or all. See also the tutorial above for more argument variations.

app

my $app = app;

The Mojolicious::Lite application.

del

my $route = del '/:foo' => sub {...};

Generate route with "delete" in Mojolicious::Routes::Route, matching only DELETE requests. See also the tutorial above for more argument variations.

get

my $route = get '/:foo' => sub {...};

Generate route with "get" in Mojolicious::Routes::Route, matching only GET requests. See also the tutorial above for more argument variations.

group

group {...};

Start a new route group.

helper

helper foo => sub {...};

Alias for "helper" in Mojolicious.

hook

hook after_dispatch => sub {...};

Alias for "hook" in Mojolicious.

options

my $route = options '/:foo' => sub {...};

Generate route with "options" in Mojolicious::Routes::Route, matching only OPTIONS requests. See also the tutorial above for more argument variations.

patch

my $route = patch '/:foo' => sub {...};

Generate route with "patch" in Mojolicious::Routes::Route, matching only PATCH requests. See also the tutorial above for more argument variations.

plugin

plugin 'SomeThing';

Alias for "plugin" in Mojolicious.

post

my $route = post '/:foo' => sub {...};

Generate route with "post" in Mojolicious::Routes::Route, matching only POST requests. See also the tutorial above for more argument variations.

put

my $route = put '/:foo' => sub {...};

Generate route with "put" in Mojolicious::Routes::Route, matching only PUT requests. See also the tutorial above for more argument variations.

under

my $route = under sub {...};
my $route = under '/:foo';

Generate bridge with "under" in Mojolicious::Routes::Route, to which all following routes are automatically appended. See also the tutorial above for more argument variations.

websocket

my $route = websocket '/:foo' => sub {...};

Generate route with "websocket" in Mojolicious::Routes::Route, matching only WebSocket handshakes. See also the tutorial above for more argument variations.

ATTRIBUTES

Mojolicious::Lite inherits all attributes from Mojolicious.

METHODS

Mojolicious::Lite inherits all methods from Mojolicious.

SEE ALSO

Mojolicious, Mojolicious::Guides, http://mojolicio.us.