957 lines
27 KiB
Plaintext
957 lines
27 KiB
Plaintext
|
|
=encoding utf8
|
|
|
|
=head1 NAME
|
|
|
|
Mojolicious::Guides::Tutorial - Get started with Mojolicious
|
|
|
|
=head1 TUTORIAL
|
|
|
|
A quick example-driven introduction to the wonders of L<Mojolicious::Lite>. Almost everything you'll learn here also
|
|
applies to full L<Mojolicious> applications.
|
|
|
|
This is only the first of the L<Mojolicious::Guides>. Other guides delve deeper into topics like
|
|
L<growing|Mojolicious::Guides::Growing> a L<Mojolicious::Lite> prototype into a well-structured L<Mojolicious>
|
|
application, L<routing|Mojolicious::Guides::Routing>, L<rendering|Mojolicious::Guides::Rendering> and more. It is
|
|
highly encouraged that readers continue on to the remaining guides after reading this one.
|
|
|
|
=head2 Hello World
|
|
|
|
A simple Hello World application can look like this, L<strict>, L<warnings>, L<utf8> and Perl 5.16 L<features|feature>
|
|
are automatically enabled and a few L<functions|Mojolicious::Lite/"FUNCTIONS"> imported, when you use
|
|
L<Mojolicious::Lite>, turning your script into a full featured web application.
|
|
|
|
#!/usr/bin/env perl
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
get '/' => sub ($c) {
|
|
$c->render(text => 'Hello World!');
|
|
};
|
|
|
|
app->start;
|
|
|
|
With L<Mojolicious::Command::Author::generate::lite_app> there is also a helper command to generate a small example
|
|
application.
|
|
|
|
$ mojo generate lite-app myapp.pl
|
|
|
|
=head2 Commands
|
|
|
|
Many different L<commands|Mojolicious::Commands/"COMMANDS"> are automatically available from the command line. CGI and
|
|
L<PSGI> environments can even be detected and will usually just work without commands.
|
|
|
|
$ ./myapp.pl daemon
|
|
Web application available at http://127.0.0.1:3000
|
|
|
|
$ ./myapp.pl daemon -l http://*:8080
|
|
Web application available at http://127.0.0.1:8080
|
|
|
|
$ ./myapp.pl cgi
|
|
...CGI output...
|
|
|
|
$ ./myapp.pl get /
|
|
Hello World!
|
|
|
|
$ ./myapp.pl
|
|
...List of available commands (or automatically detected environment)...
|
|
|
|
A call to L<Mojolicious/"start"> (C<app-E<gt>start>), which starts the command system, should be the last expression in
|
|
your application, because its return value can be significant.
|
|
|
|
# Use @ARGV to pick a command
|
|
app->start;
|
|
|
|
# Start the "daemon" command
|
|
app->start('daemon', '-l', 'http://*:8080');
|
|
|
|
=head2 Reloading
|
|
|
|
Your application will automatically reload itself if you start it with the L<morbo> development web server, so you
|
|
don't have to restart the server after every change.
|
|
|
|
$ morbo ./myapp.pl
|
|
Web application available at http://127.0.0.1:3000
|
|
|
|
For more information about how to deploy your application see also L<Mojolicious::Guides::Cookbook/"DEPLOYMENT">.
|
|
|
|
=head2 Routes
|
|
|
|
Routes are basically just fancy paths that can contain different kinds of placeholders and usually lead to an action,
|
|
if they match the path part of the request URL. The first argument passed to all actions (C<$c>) is a
|
|
L<Mojolicious::Controller> object, containing both the HTTP request and response.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Route leading to an action that renders some text
|
|
get '/foo' => sub ($c) {
|
|
$c->render(text => 'Hello World!');
|
|
};
|
|
|
|
app->start;
|
|
|
|
Response content is often generated by actions with L<Mojolicious::Controller/"render">, but more about that later.
|
|
|
|
=head2 GET/POST parameters
|
|
|
|
All C<GET> and C<POST> parameters sent with the request are accessible via L<Mojolicious::Controller/"param">.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# /foo?user=sri
|
|
get '/foo' => sub ($c) {
|
|
my $user = $c->param('user');
|
|
$c->render(text => "Hello $user.");
|
|
};
|
|
|
|
app->start;
|
|
|
|
=head2 Stash and templates
|
|
|
|
The L<Mojolicious::Controller/"stash"> is used to pass data to templates, which can be inlined in the C<DATA> section.
|
|
A few stash values like C<template>, C<text> and C<data> are reserved and will be used by
|
|
L<Mojolicious::Controller/"render"> to decide how a response should be generated.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Route leading to an action that renders a template
|
|
get '/foo' => sub ($c) {
|
|
$c->stash(one => 23);
|
|
$c->render(template => 'magic', two => 24);
|
|
};
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ magic.html.ep
|
|
The magic numbers are <%= $one %> and <%= $two %>.
|
|
|
|
For more information about templates see also L<Mojolicious::Guides::Rendering/"Embedded Perl">.
|
|
|
|
=head2 HTTP
|
|
|
|
L<Mojolicious::Controller/"req"> and L<Mojolicious::Controller/"res"> give you full access to all HTTP features and
|
|
information.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Access request information
|
|
get '/agent' => sub ($c) {
|
|
my $host = $c->req->url->to_abs->host;
|
|
my $ua = $c->req->headers->user_agent;
|
|
$c->render(text => "Request by $ua reached $host.");
|
|
};
|
|
|
|
# Echo the request body and send custom header with response
|
|
post '/echo' => sub ($c) {
|
|
$c->res->headers->header('X-Bender' => 'Bite my shiny metal ass!');
|
|
$c->render(data => $c->req->body);
|
|
};
|
|
|
|
app->start;
|
|
|
|
You can test the more advanced examples right from the command line with L<Mojolicious::Command::get>.
|
|
|
|
$ ./myapp.pl get -v -M POST -c 'test' /echo
|
|
|
|
=head2 JSON
|
|
|
|
JSON is the most commonly used data-interchange format for web services. L<Mojolicious> loves JSON and comes with the
|
|
possibly fastest pure-Perl implementation L<Mojo::JSON> built right in, which is accessible through
|
|
L<Mojo::Message/"json"> as well as the reserved stash value C<json>.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Modify the received JSON document and return it
|
|
put '/reverse' => sub ($c) {
|
|
my $hash = $c->req->json;
|
|
$hash->{message} = reverse $hash->{message};
|
|
$c->render(json => $hash);
|
|
};
|
|
|
|
app->start;
|
|
|
|
You can send JSON documents from the command line with L<Mojolicious::Command::get>.
|
|
|
|
$ ./myapp.pl get -M PUT -c '{"message":"Hello Mojo!"}' /reverse
|
|
|
|
=head2 Built-in C<exception> and C<not_found> pages
|
|
|
|
During development you will encounter these pages whenever you make a mistake, they are gorgeous and contain a lot of
|
|
valuable information that will aid you in debugging your application.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Not found (404)
|
|
get '/missing' => sub ($c) {
|
|
$c->render(template => 'does_not_exist');
|
|
};
|
|
|
|
# Exception (500)
|
|
get '/dies' => sub { die 'Intentional error' };
|
|
|
|
app->start;
|
|
|
|
You can even use CSS selectors with L<Mojolicious::Command::get> to extract only the information you're actually
|
|
interested in.
|
|
|
|
$ ./myapp.pl get /dies '#error'
|
|
|
|
And don't worry about revealing too much information on these pages, they are only available during development, and
|
|
will be replaced automatically with pages that don't reveal any sensitive information in a production environment.
|
|
|
|
=head2 Route names
|
|
|
|
All routes can have a name associated with them, this allows automatic template detection and backreferencing with
|
|
L<Mojolicious::Controller/"url_for">, on which many methods and helpers like
|
|
L<Mojolicious::Plugin::TagHelpers/"link_to"> rely.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Render the template "index.html.ep"
|
|
get '/' => sub ($c) {
|
|
$c->render;
|
|
} => 'index';
|
|
|
|
# Render the template "hello.html.ep"
|
|
get '/hello';
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ index.html.ep
|
|
<%= link_to Hello => 'hello' %>.
|
|
<%= link_to Reload => 'index' %>.
|
|
|
|
@@ hello.html.ep
|
|
Hello World!
|
|
|
|
Nameless routes get an automatically generated one assigned that is simply equal to the route itself without non-word
|
|
characters.
|
|
|
|
=head2 Layouts
|
|
|
|
Templates can have layouts too, you just select one with the helper L<Mojolicious::Plugin::DefaultHelpers/"layout"> and
|
|
place the result of the current template with the helper L<Mojolicious::Plugin::DefaultHelpers/"content">.
|
|
|
|
use Mojolicious::Lite;
|
|
|
|
get '/with_layout';
|
|
|
|
app->start;
|
|
__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>
|
|
|
|
The stash or helpers like L<Mojolicious::Plugin::DefaultHelpers/"title"> can be used to pass additional data to the
|
|
layout.
|
|
|
|
=head2 Blocks
|
|
|
|
Template blocks can be used like normal Perl functions and are always delimited by the C<begin> and C<end> keywords,
|
|
they are the foundation for many helpers.
|
|
|
|
use Mojolicious::Lite;
|
|
|
|
get '/with_block' => 'block';
|
|
|
|
app->start;
|
|
__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://mojolicious.org', 'Mojolicious')
|
|
%= $link->('http://catalystframework.org', 'Catalyst')
|
|
</body>
|
|
</html>
|
|
|
|
=head2 Helpers
|
|
|
|
Helpers are little functions you can create with the keyword L<Mojolicious::Lite/"helper"> and reuse throughout your
|
|
whole application, from actions to templates.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# A helper to identify visitors
|
|
helper whois => sub ($c) {
|
|
my $agent = $c->req->headers->user_agent || 'Anonymous';
|
|
my $ip = $c->tx->remote_address;
|
|
return "$agent ($ip)";
|
|
};
|
|
|
|
# Use helper in action and template
|
|
get '/secret' => sub ($c) {
|
|
my $user = $c->whois;
|
|
$c->app->log->debug("Request from $user");
|
|
};
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ secret.html.ep
|
|
We know who you are <%= whois %>.
|
|
|
|
A list of all built-in ones can be found in L<Mojolicious::Plugin::DefaultHelpers> and
|
|
L<Mojolicious::Plugin::TagHelpers>.
|
|
|
|
=head2 Plugins
|
|
|
|
Plugins are application extensions that help with code sharing and organization. You can load a plugin with the keyword
|
|
L<Mojolicious::Lite/"plugin">, which can omit the C<Mojolicious::Plugin::> part of the name, and optionally provide
|
|
configuration for the plugin.
|
|
|
|
use Mojolicious::Lite;
|
|
|
|
plugin Config => {file => '/etc/myapp.conf', default => {foo => 'bar'}};
|
|
|
|
# Return configured foo value, or default if no configuration file
|
|
get '/foo' => sub ($c) {
|
|
my $foo = $c->app->config('foo');
|
|
$c->render(json => {foo => $foo});
|
|
};
|
|
|
|
app->start;
|
|
|
|
L<Mojolicious::Plugin::Config> is a built-in plugin which can populate L<Mojolicious/"config"> using a config file.
|
|
Plugins can also set up routes, hooks, handlers, or even load other plugins. A list of built-in plugins can be found at
|
|
L<Mojolicious::Plugins/"PLUGINS">, and many more are available from
|
|
L<CPAN|https://metacpan.org/search?q=Mojolicious+Plugin>.
|
|
|
|
=head2 Placeholders
|
|
|
|
Route placeholders allow capturing parts of a request path until a C</> or C<.> separator occurs, similar to the
|
|
regular expression C<([^/.]+)>. Results are accessible via L<Mojolicious::Controller/"stash"> and
|
|
L<Mojolicious::Controller/"param">.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# /foo/test
|
|
# /foo/test123
|
|
get '/foo/:bar' => sub ($c) {
|
|
my $bar = $c->stash('bar');
|
|
$c->render(text => "Our :bar placeholder matched $bar");
|
|
};
|
|
|
|
# /testsomething/foo
|
|
# /test123something/foo
|
|
get '/<:bar>something/foo' => sub ($c) {
|
|
my $bar = $c->param('bar');
|
|
$c->render(text => "Our :bar placeholder matched $bar");
|
|
};
|
|
|
|
app->start;
|
|
|
|
To separate them from the surrounding text, you can surround your placeholders with C<E<lt>> and C<E<gt>>, which also
|
|
makes the colon prefix optional.
|
|
|
|
=head2 Relaxed Placeholders
|
|
|
|
Relaxed placeholders allow matching of everything until a C</> occurs, similar to the regular expression C<([^/]+)>.
|
|
|
|
use Mojolicious::Lite;
|
|
|
|
# /hello/test
|
|
# /hello/test.html
|
|
get '/hello/#you' => 'groovy';
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ groovy.html.ep
|
|
Your name is <%= $you %>.
|
|
|
|
=head2 Wildcard placeholders
|
|
|
|
Wildcard placeholders allow matching absolutely everything, including C</> and C<.>, similar to the regular expression
|
|
C<(.+)>.
|
|
|
|
use Mojolicious::Lite;
|
|
|
|
# /hello/test
|
|
# /hello/test123
|
|
# /hello/test.123/test/123
|
|
get '/hello/*you' => 'groovy';
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ groovy.html.ep
|
|
Your name is <%= $you %>.
|
|
|
|
=head2 HTTP methods
|
|
|
|
Routes can be restricted to specific request methods with different keywords like L<Mojolicious::Lite/"get"> and
|
|
L<Mojolicious::Lite/"any">.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# GET /hello
|
|
get '/hello' => sub ($c) {
|
|
$c->render(text => 'Hello World!');
|
|
};
|
|
|
|
# PUT /hello
|
|
put '/hello' => sub ($c) {
|
|
my $size = length $c->req->body;
|
|
$c->render(text => "You uploaded $size bytes to /hello.");
|
|
};
|
|
|
|
# GET|POST|PATCH /bye
|
|
any ['GET', 'POST', 'PATCH'] => '/bye' => sub ($c) {
|
|
$c->render(text => 'Bye World!');
|
|
};
|
|
|
|
# * /whatever
|
|
any '/whatever' => sub ($c) {
|
|
my $method = $c->req->method;
|
|
$c->render(text => "You called /whatever with $method.");
|
|
};
|
|
|
|
app->start;
|
|
|
|
=head2 Optional placeholders
|
|
|
|
All placeholders require a value, but by assigning them default values you can make capturing optional.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# /hello
|
|
# /hello/Sara
|
|
get '/hello/:name' => {name => 'Sebastian', day => 'Monday'} => sub ($c) {
|
|
$c->render(template => 'groovy', format => 'txt');
|
|
};
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ groovy.txt.ep
|
|
My name is <%= $name %> and it is <%= $day %>.
|
|
|
|
Default values that don't belong to a placeholder simply get merged into the stash all the time.
|
|
|
|
=head2 Restrictive placeholders
|
|
|
|
A very easy way to make placeholders more restrictive are alternatives, you just make a list of possible values.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# /test
|
|
# /123
|
|
any '/:foo' => [foo => ['test', '123']] => sub ($c) {
|
|
my $foo = $c->param('foo');
|
|
$c->render(text => "Our :foo placeholder matched $foo");
|
|
};
|
|
|
|
app->start;
|
|
|
|
All placeholders get compiled to a regular expression internally, this process can also be customized. Just make sure
|
|
not to use C<^> and C<$>, or capturing groups C<(...)>, non-capturing groups C<(?:...)> are fine though.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# /1
|
|
# /123
|
|
any '/:bar' => [bar => qr/\d+/] => sub ($c) {
|
|
my $bar = $c->param('bar');
|
|
$c->render(text => "Our :bar placeholder matched $bar");
|
|
};
|
|
|
|
app->start;
|
|
|
|
You can take a closer look at all the generated regular expressions with the command L<Mojolicious::Command::routes>.
|
|
|
|
$ ./myapp.pl routes -v
|
|
|
|
=head2 Under
|
|
|
|
Authentication and code shared between multiple routes can be realized easily with routes generated by
|
|
L<Mojolicious::Lite/"under">. All following routes are only evaluated if the callback returned a true value.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Authenticate based on name parameter
|
|
under sub ($c) {
|
|
|
|
# Authenticated
|
|
my $name = $c->param('name') || '';
|
|
return 1 if $name eq 'Bender';
|
|
|
|
# Not authenticated
|
|
$c->render(template => 'denied');
|
|
return undef;
|
|
};
|
|
|
|
# Only reached when authenticated
|
|
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 it.
|
|
|
|
use Mojolicious::Lite;
|
|
|
|
# /foo
|
|
under '/foo';
|
|
|
|
# /foo/bar
|
|
get '/bar' => {text => 'foo bar'};
|
|
|
|
# /foo/baz
|
|
get '/baz' => {text => 'foo baz'};
|
|
|
|
# / (reset)
|
|
under '/' => {msg => 'whatever'};
|
|
|
|
# /bar
|
|
get '/bar' => {inline => '<%= $msg %> works'};
|
|
|
|
app->start;
|
|
|
|
You can also group related routes with L<Mojolicious::Lite/"group">, which allows nesting of routes generated with
|
|
L<Mojolicious::Lite/"under">.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Global logic shared by all routes
|
|
under sub ($c) {
|
|
return 1 if $c->req->headers->header('X-Bender');
|
|
$c->render(text => "You're not Bender.");
|
|
return undef;
|
|
};
|
|
|
|
# Admin section
|
|
group {
|
|
|
|
# Local logic shared only by routes in this group
|
|
under '/admin' => sub ($c) {
|
|
return 1 if $c->req->headers->header('X-Awesome');
|
|
$c->render(text => "You're not awesome enough.");
|
|
return undef;
|
|
};
|
|
|
|
# GET /admin/dashboard
|
|
get '/dashboard' => {text => 'Nothing to see here yet.'};
|
|
};
|
|
|
|
# GET /welcome
|
|
get '/welcome' => {text => 'Hi Bender.'};
|
|
|
|
app->start;
|
|
|
|
=head2 Formats
|
|
|
|
Formats can be automatically detected from file extensions like C<.html>, they are used to find the right template and
|
|
generate the correct C<Content-Type> header.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# /detection
|
|
# /detection.html
|
|
# /detection.txt
|
|
get '/detection' => sub ($c) {
|
|
$c->render(template => 'detected');
|
|
};
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ detected.html.ep
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head><title>Detected</title></head>
|
|
<body>HTML was detected.</body>
|
|
</html>
|
|
|
|
@@ detected.txt.ep
|
|
TXT was detected.
|
|
|
|
The default format is C<html>, and restrictive placeholders can be used to limit possible values.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# /hello.json
|
|
# /hello.txt
|
|
get '/hello' => [format => ['json', 'txt']] => sub ($c) {
|
|
return $c->render(json => {hello => 'world'})
|
|
if $c->stash('format') eq 'json';
|
|
$c->render(text => 'hello world');
|
|
};
|
|
|
|
app->start;
|
|
|
|
Or you can just disable format detection with a special type of restrictive placeholder.
|
|
|
|
use Mojolicious::Lite;
|
|
|
|
# /hello
|
|
get '/hello' => [format => 0] => {text => 'No format detection.'};
|
|
|
|
# Disable detection and allow the following routes to re-enable it on demand
|
|
under [format => 0];
|
|
|
|
# /foo
|
|
get '/foo' => {text => 'No format detection again.'};
|
|
|
|
# /bar.txt
|
|
get '/bar' => [format => 'txt'] => {text => ' Just one format.'};
|
|
|
|
app->start;
|
|
|
|
=head2 Content negotiation
|
|
|
|
For resources with different representations and that require truly RESTful content negotiation you can also use
|
|
L<Mojolicious::Plugin::DefaultHelpers/"respond_to">.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# /hello (Accept: application/json)
|
|
# /hello (Accept: application/xml)
|
|
# /hello.json
|
|
# /hello.xml
|
|
# /hello?format=json
|
|
# /hello?format=xml
|
|
get '/hello' => sub ($c) {
|
|
$c->respond_to(
|
|
json => {json => {hello => 'world'}},
|
|
xml => {text => '<hello>world</hello>'},
|
|
any => {data => '', status => 204}
|
|
);
|
|
};
|
|
|
|
app->start;
|
|
|
|
MIME type mappings can be extended or changed easily with L<Mojolicious/"types">.
|
|
|
|
app->types->type(rdf => 'application/rdf+xml');
|
|
|
|
=head2 Static files
|
|
|
|
Similar to templates, but with only a single file extension and optional Base64 encoding, static files can be inlined
|
|
in the C<DATA> section and are served automatically.
|
|
|
|
use Mojolicious::Lite;
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ something.js
|
|
alert('hello!');
|
|
|
|
@@ test.txt (base64)
|
|
dGVzdCAxMjMKbGFsYWxh
|
|
|
|
External static files are not limited to a single file extension and will be served automatically from a C<public>
|
|
directory if it exists.
|
|
|
|
$ mkdir public
|
|
$ mv something.js public/something.js
|
|
$ mv mojolicious.tar.gz public/mojolicious.tar.gz
|
|
|
|
Both have a higher precedence than routes for C<GET> and C<HEAD> requests. Content negotiation with C<Range>,
|
|
C<If-None-Match> and C<If-Modified-Since> headers is supported as well and can be tested very easily with
|
|
L<Mojolicious::Command::get>.
|
|
|
|
$ ./myapp.pl get /something.js -v -H 'Range: bytes=2-4'
|
|
|
|
=head2 External templates
|
|
|
|
External templates will be searched by the renderer in a C<templates> directory if it exists.
|
|
|
|
$ mkdir -p templates/foo
|
|
$ echo 'Hello World!' > templates/foo/bar.html.ep
|
|
|
|
They have a higher precedence than templates in the C<DATA> section.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Render template "templates/foo/bar.html.ep"
|
|
any '/external' => sub ($c) {
|
|
$c->render(template => 'foo/bar');
|
|
};
|
|
|
|
app->start;
|
|
|
|
=head2 Home
|
|
|
|
You can use L<Mojolicious/"home"> to interact with the directory your application considers its home. This is the
|
|
directory it will search for C<public> and C<templates> directories, but you can use it to store all sorts of
|
|
application specific data.
|
|
|
|
$ mkdir cache
|
|
$ echo 'Hello World!' > cache/hello.txt
|
|
|
|
There are many useful methods L<Mojo::Home> inherits from L<Mojo::File>, like L<Mojo::File/"child"> and
|
|
L<Mojo::File/"slurp">, that will help you keep your application portable across many different operating systems.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Load message into memory
|
|
my $hello = app->home->child('cache', 'hello.txt')->slurp;
|
|
|
|
# Display message
|
|
get '/' => sub ($c) {
|
|
$c->render(text => $hello);
|
|
};
|
|
|
|
You can also introspect your application from the command line with L<Mojolicious::Command::eval>.
|
|
|
|
$ ./myapp.pl eval -v 'app->home'
|
|
|
|
=head2 Conditions
|
|
|
|
Conditions such as C<agent> and C<host> from L<Mojolicious::Plugin::HeaderCondition> allow even more powerful route
|
|
constructs.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Firefox
|
|
get '/foo' => (agent => qr/Firefox/) => sub ($c) {
|
|
$c->render(text => 'Congratulations, you are using a cool browser.');
|
|
};
|
|
|
|
# Internet Explorer
|
|
get '/foo' => (agent => qr/Internet Explorer/) => sub ($c) {
|
|
$c->render(text => 'Dude, you really need to upgrade to Firefox.');
|
|
};
|
|
|
|
# http://mojolicious.org/bar
|
|
get '/bar' => (host => 'mojolicious.org') => sub ($c) {
|
|
$c->render(text => 'Hello Mojolicious.');
|
|
};
|
|
|
|
app->start;
|
|
|
|
=head2 Sessions
|
|
|
|
Cookie-based sessions just work out of the box, as soon as you start using them through the helper
|
|
L<Mojolicious::Plugin::DefaultHelpers/"session">. Just be aware that all session data gets serialized with
|
|
L<Mojo::JSON> and stored client-side, with a cryptographic signature to prevent tampering.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Access session data in action and template
|
|
get '/counter' => sub ($c) {
|
|
$c->session->{counter}++;
|
|
};
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ counter.html.ep
|
|
Counter: <%= session 'counter' %>
|
|
|
|
Note that you should use custom L<Mojolicious/"secrets"> to make signed cookies really tamper resistant.
|
|
|
|
app->secrets(['My secret passphrase here']);
|
|
|
|
=head2 File uploads
|
|
|
|
All files uploaded via C<multipart/form-data> request are automatically available as L<Mojo::Upload> objects from
|
|
L<Mojolicious::Controller/"param">. And you don't have to worry about memory usage, because all files above 250KiB will
|
|
be automatically streamed into a temporary file. To build HTML forms more efficiently, you can also use tag helpers
|
|
like L<Mojolicious::Plugin::TagHelpers/"form_for">.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Upload form in DATA section
|
|
get '/' => 'form';
|
|
|
|
# Multipart upload handler
|
|
post '/upload' => sub ($c) {
|
|
|
|
# Check file size
|
|
return $c->render(text => 'File is too big.', status => 200) if $c->req->is_limit_exceeded;
|
|
|
|
# Process uploaded file
|
|
return $c->redirect_to('form') unless my $example = $c->param('example');
|
|
my $size = $example->size;
|
|
my $name = $example->filename;
|
|
$c->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 16MiB by default, which you can tweak with the
|
|
attribute L<Mojolicious/"max_request_size">.
|
|
|
|
# Increase limit to 1GiB
|
|
app->max_request_size(1073741824);
|
|
|
|
=head2 User agent
|
|
|
|
With L<Mojo::UserAgent>, which is available through the helper L<Mojolicious::Plugin::DefaultHelpers/"ua">, there's a
|
|
full featured HTTP and WebSocket user agent built right in. Especially in combination with L<Mojo::JSON> and
|
|
L<Mojo::DOM> this can be a very powerful tool.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Blocking
|
|
get '/headers' => sub ($c) {
|
|
my $url = $c->param('url') || 'https://mojolicious.org';
|
|
my $dom = $c->ua->get($url)->result->dom;
|
|
$c->render(json => $dom->find('h1, h2, h3')->map('text')->to_array);
|
|
};
|
|
|
|
# Non-blocking
|
|
get '/title' => sub ($c) {
|
|
$c->ua->get('mojolicious.org' => sub ($ua, $tx) {
|
|
$c->render(data => $tx->result->dom->at('title')->text);
|
|
});
|
|
};
|
|
|
|
# Concurrent non-blocking
|
|
get '/titles' => sub ($c) {
|
|
my $mojo = $c->ua->get_p('https://mojolicious.org');
|
|
my $cpan = $c->ua->get_p('https://metacpan.org');
|
|
Mojo::Promise->all($mojo, $cpan)->then(sub ($mojo, $cpan) {
|
|
$c->render(json => {
|
|
mojo => $mojo->[0]->result->dom->at('title')->text,
|
|
cpan => $cpan->[0]->result->dom->at('title')->text
|
|
});
|
|
})->wait;
|
|
};
|
|
|
|
app->start;
|
|
|
|
For more information about the user agent see also L<Mojolicious::Guides::Cookbook/"USER AGENT">.
|
|
|
|
=head2 WebSockets
|
|
|
|
WebSocket applications have never been this simple before. Just receive messages by subscribing to events such as
|
|
L<Mojo::Transaction::WebSocket/"json"> with L<Mojolicious::Controller/"on"> and return them with
|
|
L<Mojolicious::Controller/"send">.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
websocket '/echo' => sub ($c) {
|
|
$c->on(json => sub ($c, $hash) {
|
|
$hash->{msg} = "echo: $hash->{msg}";
|
|
$c->send({json => $hash});
|
|
});
|
|
};
|
|
|
|
get '/' => 'index';
|
|
|
|
app->start;
|
|
__DATA__
|
|
|
|
@@ index.html.ep
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Echo</title>
|
|
<script>
|
|
var ws = new WebSocket('<%= url_for('echo')->to_abs %>');
|
|
ws.onmessage = function (event) {
|
|
document.body.innerHTML += JSON.parse(event.data).msg;
|
|
};
|
|
ws.onopen = function (event) {
|
|
ws.send(JSON.stringify({msg: 'I ♥ Mojolicious!'}));
|
|
};
|
|
</script>
|
|
</head>
|
|
</html>
|
|
|
|
For more information about real-time web features see also L<Mojolicious::Guides::Cookbook/"REAL-TIME WEB">.
|
|
|
|
=head2 Mode
|
|
|
|
You can use the L<Mojo::Log> object from L<Mojolicious/"log"> to portably collect debug messages and automatically
|
|
disable them later in a production setup by changing the L<Mojolicious> operating mode, which can also be retrieved
|
|
from the attribute L<Mojolicious/"mode">.
|
|
|
|
use Mojolicious::Lite -signatures;
|
|
|
|
# Prepare mode specific message during startup
|
|
my $msg = app->mode eq 'development' ? 'Development!' : 'Something else!';
|
|
|
|
get '/' => sub ($c) {
|
|
$c->app->log->debug('Rendering mode specific message');
|
|
$c->render(text => $msg);
|
|
};
|
|
|
|
app->log->debug('Starting application');
|
|
app->start;
|
|
|
|
The default operating mode will usually be C<development> and can be changed with command line options or the
|
|
C<MOJO_MODE> and C<PLACK_ENV> environment variables. A mode other than C<development> will raise the log level from
|
|
C<debug> to C<info>. All messages will be written to C<STDERR> by default.
|
|
|
|
$ ./myapp.pl daemon -m production
|
|
|
|
Mode changes also affect a few other aspects of the framework, such as the built-in C<exception> and C<not_found>
|
|
pages. Once you switch modes from C<development> to C<production>, no sensitive information will be revealed on those
|
|
pages anymore.
|
|
|
|
=head2 Testing
|
|
|
|
Testing your application is as easy as creating a C<t> directory and filling it with normal Perl tests like
|
|
C<t/basic.t>, which can be a lot of fun thanks to L<Test::Mojo>.
|
|
|
|
use Test::More;
|
|
use Mojo::File qw(curfile);
|
|
use Test::Mojo;
|
|
|
|
# Portably point to "../myapp.pl"
|
|
my $script = curfile->dirname->sibling('myapp.pl');
|
|
|
|
my $t = Test::Mojo->new($script);
|
|
$t->get_ok('/')->status_is(200)->content_like(qr/Funky/);
|
|
|
|
done_testing();
|
|
|
|
Just run your tests with L<prove>.
|
|
|
|
$ prove -l -v
|
|
$ prove -l -v t/basic.t
|
|
|
|
=head1 MORE
|
|
|
|
You can continue with L<Mojolicious::Guides> now or take a look at the L<Mojolicious
|
|
wiki|https://github.com/mojolicious/mojo/wiki>, which contains a lot more documentation and examples by many different
|
|
authors.
|
|
|
|
=head1 SUPPORT
|
|
|
|
If you have any questions the documentation might not yet answer, don't hesitate to ask in the
|
|
L<Forum|https://forum.mojolicious.org> or the official IRC channel C<#mojo> on C<chat.freenode.net>
|
|
(L<chat now!|https://webchat.freenode.net/#mojo>).
|
|
|
|
=cut
|