Mojolicious::Lite - Real-time micro web framework
# 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;
Mojolicious::Lite is a micro real-time web framework built around Mojolicious.
A quick example driven introduction to the wonders of Mojolicious::Lite. Most of what you'll learn here also applies to normal Mojolicious applications.
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;
There is also a helper command to generate a small example application.
$ mojo generate lite_app
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)...
The app->start call that starts the Mojolicious command system can be customized to override normal @ARGV use.
@ARGV
app->start('cgi');
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
$ morbo myapp.pl Server available at http://127.0.0.1:3000.
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.
$self
# /foo get '/foo' => sub { my $self = shift; $self->render(text => 'Hello World!'); };
All GET and POST parameters are accessible via param.
GET
POST
param
# /foo?user=sri get '/foo' => sub { my $self = shift; my $user = $self->param('user'); $self->render(text => "Hello $user."); };
The stash is used to pass data to templates, which can be inlined in the DATA section.
stash
DATA
# /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.
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); };
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.
url_for
link_to
form_for
# / 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!
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>
Template blocks can be used like normal Perl functions and are always delimited by the begin and end keywords.
begin
end
# /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>
The content_for helper can be used to pass around blocks of captured content.
content_for
# /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>
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 %>.
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 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 %>.
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"); };
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 %>.
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 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'); };
For resources with different representations and that require truly RESTful content negotiation you can also use respond_to.
RESTful
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');
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.
under
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.
group
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 such as agent and host from Mojolicious::Plugin::HeaderCondition allow even more powerful route constructs.
agent
host
# /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.'); };
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' %>
Note that you should use a custom secret to make signed cookies really secure.
secret
app->secret('My secret passphrase here');
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.
multipart/form-data
250KB
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.
5MB
MOJO_MAX_MESSAGE_SIZE
# Increase limit to 1GB $ENV{MOJO_MAX_MESSAGE_SIZE} = 1073741824;
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); };
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.
message
External templates will be searched by the renderer in a templates directory.
templates
# /external any '/external' => sub { my $self = shift; # templates/foo/bar.html.ep $self->render('foo/bar'); };
Static files will be automatically served from the DATA section (even Base64 encoded) or a public directory if it exists.
public
@@ something.js alert('hello!'); @@ test.txt (base64) dGVzdCAxMjMKbGFsYWxh $ mkdir public $ mv something.js public/something.js
Testing your application is as easy as creating a t directory and filling it with normal Perl unit tests.
t
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.
test
$ ./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');
To disable debug messages later in a production setup you can change the Mojolicious mode, default will be development.
development
$ ./myapp.pl -m production
Mojo::Log messages will be automatically written to STDERR or a log/$mode.log file if a log directory exists.
STDERR
log/$mode.log
log
$ 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!'); });
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
You can continue with Mojolicious::Guides now, and don't forget to have fun!
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.
DELETE
get
my $route = get '/:foo' => sub {...};
Generate route matching only GET requests. See also the tutorial above for more argument variations.
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.
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.
PUT
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.
WebSocket
Mojolicious::Lite inherits all attributes from Mojolicious.
Mojolicious::Lite inherits all methods from Mojolicious.
Mojolicious, Mojolicious::Guides, http://mojolicio.us.
To install Mojolicious, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Mojolicious
CPAN shell
perl -MCPAN -e shell install Mojolicious
For more information on module installation, please visit the detailed CPAN module installation guide.