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 --listen 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 an instance of Mojolicious::Controller 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
.
# /foo?user=sri
get '/foo' => sub {
my $self = shift;
my $user = $self->param('user');
$self->render(text => "Hello $user.");
};
Stash and templates
The stash
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
Mojo::Message::Request and Mojo::Message::Response 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
, link_to
and form_for
. 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.
# /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 content_for
helper 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 will be stored by name in the stash
and param
.
# /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 /bye
get '/bye' => sub {
my $self = shift;
$self->render(text => 'Bye.');
};
# POST /bye
post '/bye' => sub {
my $self = shift;
$self->render(text => 'Bye.');
};
# GET|POST|DELETE /bye
any ['get', 'post', 'delete'] => '/bye' => sub {
my $self = shift;
$self->render(text => 'Bye.');
};
# * /baz
any '/baz' => sub {
my $self = shift;
my $method = $self->req->method;
$self->render(text => "You called /baz 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
.
# /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.
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
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 instances. 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;
any '/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
if (my $example = $self->req->upload('example')) {
my $size = $example->size;
my $name = $example->filename;
$self->render(text => "Thanks for uploading $size byte file $name.");
}
};
app->start;
__DATA__
@@ upload.html.ep
<!DOCTYPE html>
<html>
<head><title>Upload</title></head>
<body>
% my @attrs = (method => 'POST', enctype => 'multipart/form-data');
%= form_for upload => @attrs => 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 Mojo::UserAgent 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_message("echo: $message");
});
};
The message
event 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 --mode 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 instance 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!');
});
Growing
In case a lite app needs to grow, lite and real Mojolicious applications can be easily mixed to make the transition process very smooth.
package MyApp::Foo;
use Mojo::Base 'Mojolicious::Controller';
sub index {
my $self = shift;
$self->render(text => 'It works.');
}
package main;
use Mojolicious::Lite;
get '/bar' => sub {
my $self = shift;
$self->render(text => 'This too.');
};
app->routes->namespace('MyApp');
app->routes->route('/foo/:action')->via('GET')->to('foo#index');
app->start;
There is also a helper command to generate a full Mojolicious example that will let you explore the astonishing similarities between Mojolicious::Lite and Mojolicious applications. Both share about 99% of the same code, so almost everything you learned in this tutorial applies there too. :)
$ mojo generate app
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 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 matching only DELETE
requests. See also the tutorial above for more argument variations.
get
my $route = get '/:foo' => sub {...};
Generate route matching only GET
requests. See also the tutorial above for more argument variations.
group
group {...};
Start a new route group. Note that this function is EXPERIMENTAL and might change without warning!
helper
helper foo => sub {...};
Alias for "helper" in Mojolicious.
hook
hook after_dispatch => sub {...};
Alias for "hook" in Mojolicious.
plugin
plugin 'SomeThing';
Alias for "plugin" in Mojolicious.
post
my $route = post '/:foo' => sub {...};
Generate route matching only POST
requests. See also the tutorial above for more argument variations.
put
my $route = put '/:foo' => sub {...};
Generate 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 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 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.