add files
|
1 |
package Mojolicious::Lite; |
2 |
use Mojo::Base 'Mojolicious'; |
|
3 | ||
4 |
# "Bender: Bite my shiny metal ass!" |
|
5 |
use File::Basename qw(basename dirname); |
|
6 |
use File::Spec::Functions 'catdir'; |
|
7 |
use Mojo::UserAgent::Server; |
|
8 |
use Mojo::Util 'monkey_patch'; |
|
9 | ||
10 |
sub import { |
|
11 | ||
12 |
# Remember executable for later |
|
13 |
$ENV{MOJO_EXE} ||= (caller)[1]; |
|
14 | ||
15 |
# Reuse home directory if possible |
|
16 |
local $ENV{MOJO_HOME} = catdir(split '/', dirname $ENV{MOJO_EXE}) |
|
17 |
unless $ENV{MOJO_HOME}; |
|
18 | ||
19 |
# Initialize application class |
|
20 |
my $caller = caller; |
|
21 |
no strict 'refs'; |
|
22 |
push @{"${caller}::ISA"}, 'Mojo'; |
|
23 | ||
24 |
# Generate moniker based on filename |
|
25 |
my $moniker = basename $ENV{MOJO_EXE}; |
|
26 |
$moniker =~ s/\.(?:pl|pm|t)$//i; |
|
27 |
my $app = shift->new(moniker => $moniker); |
|
28 | ||
29 |
# Initialize routes without namespaces |
|
30 |
my $routes = $app->routes->namespaces([]); |
|
31 |
$app->static->classes->[0] = $app->renderer->classes->[0] = $caller; |
|
32 | ||
33 |
# The Mojolicious::Lite DSL |
|
34 |
my $root = $routes; |
|
35 |
for my $name (qw(any get options patch post put websocket)) { |
|
36 |
monkey_patch $caller, $name, sub { $routes->$name(@_) }; |
|
37 |
} |
|
38 |
monkey_patch $caller, $_, sub {$app} |
|
39 |
for qw(new app); |
|
40 |
monkey_patch $caller, del => sub { $routes->delete(@_) }; |
|
41 |
monkey_patch $caller, group => sub (&) { |
|
42 |
(my $old, $root) = ($root, $routes); |
|
43 |
shift->(); |
|
44 |
($routes, $root) = ($root, $old); |
|
45 |
}; |
|
46 |
monkey_patch $caller, |
|
47 |
helper => sub { $app->helper(@_) }, |
|
48 |
hook => sub { $app->hook(@_) }, |
|
49 |
plugin => sub { $app->plugin(@_) }, |
|
50 |
under => sub { $routes = $root->under(@_) }; |
|
51 | ||
52 |
# Make sure there's a default application for testing |
|
53 |
Mojo::UserAgent::Server->app($app) unless Mojo::UserAgent::Server->app; |
|
54 | ||
55 |
# Lite apps are strict! |
|
56 |
Mojo::Base->import(-strict); |
|
57 |
} |
|
58 | ||
59 |
1; |
|
60 | ||
61 |
=encoding utf8 |
|
62 | ||
63 |
=head1 NAME |
|
64 | ||
65 |
Mojolicious::Lite - Real-time micro web framework |
|
66 | ||
67 |
=head1 SYNOPSIS |
|
68 | ||
69 |
# Automatically enables "strict", "warnings", "utf8" and Perl 5.10 features |
|
70 |
use Mojolicious::Lite; |
|
71 | ||
72 |
# Route with placeholder |
|
73 |
get '/:foo' => sub { |
|
74 |
my $self = shift; |
|
75 |
my $foo = $self->param('foo'); |
|
76 |
$self->render(text => "Hello from $foo."); |
|
77 |
}; |
|
78 | ||
79 |
# Start the Mojolicious command system |
|
80 |
app->start; |
|
81 | ||
82 |
=head1 DESCRIPTION |
|
83 | ||
84 |
L<Mojolicious::Lite> is a micro real-time web framework built around |
|
85 |
L<Mojolicious>. |
|
86 | ||
87 |
=head1 TUTORIAL |
|
88 | ||
89 |
A quick example driven introduction to the wonders of L<Mojolicious::Lite>. |
|
90 |
Most of what you'll learn here also applies to normal L<Mojolicious> |
|
91 |
applications. |
|
92 | ||
93 |
=head2 Hello World |
|
94 | ||
95 |
A simple Hello World application can look like this, L<strict>, L<warnings>, |
|
96 |
L<utf8> and Perl 5.10 features are automatically enabled and a few functions |
|
97 |
imported when you use L<Mojolicious::Lite>, turning your script into a full |
|
98 |
featured web application. |
|
99 | ||
100 |
#!/usr/bin/env perl |
|
101 |
use Mojolicious::Lite; |
|
102 | ||
103 |
get '/' => sub { |
|
104 |
my $self = shift; |
|
105 |
$self->render(text => 'Hello World!'); |
|
106 |
}; |
|
107 | ||
108 |
app->start; |
|
109 | ||
110 |
There is also a helper command to generate a small example application. |
|
111 | ||
112 |
$ mojo generate lite_app myapp.pl |
|
113 | ||
114 |
=head2 Commands |
|
115 | ||
116 |
All the normal L<Mojolicious::Commands> are available from the command line. |
|
117 |
Note that CGI and L<PSGI> environments can usually be auto detected and will |
|
118 |
just work without commands. |
|
119 | ||
120 |
$ ./myapp.pl daemon |
|
121 |
Server available at http://127.0.0.1:3000. |
|
122 | ||
123 |
$ ./myapp.pl daemon -l http://*:8080 |
|
124 |
Server available at http://127.0.0.1:8080. |
|
125 | ||
126 |
$ ./myapp.pl cgi |
|
127 |
...CGI output... |
|
128 | ||
129 |
$ ./myapp.pl |
|
130 |
...List of available commands (or automatically detected environment)... |
|
131 | ||
132 |
The C<app-E<gt>start> call that starts the L<Mojolicious> command system |
|
133 |
should usually be the last expression in your application and can be |
|
134 |
customized to override normal C<@ARGV> use. |
|
135 | ||
136 |
app->start('cgi'); |
|
137 | ||
138 |
=head2 Reloading |
|
139 | ||
140 |
Your application will automatically reload itself if you start it with the |
|
141 |
C<morbo> development web server, so you don't have to restart the server after |
|
142 |
every change. |
|
143 | ||
144 |
$ morbo myapp.pl |
|
145 |
Server available at http://127.0.0.1:3000. |
|
146 | ||
147 |
For more information about how to deploy your application see also |
|
148 |
L<Mojolicious::Guides::Cookbook/"DEPLOYMENT">. |
|
149 | ||
150 |
=head2 Routes |
|
151 | ||
152 |
Routes are basically just fancy paths that can contain different kinds of |
|
153 |
placeholders and usually lead to an action. The first argument passed to all |
|
154 |
actions (the invocant C<$self>) is a L<Mojolicious::Controller> object |
|
155 |
containing both the HTTP request and response. |
|
156 | ||
157 |
use Mojolicious::Lite; |
|
158 | ||
159 |
# Route leading to an action |
|
160 |
get '/foo' => sub { |
|
161 |
my $self = shift; |
|
162 |
$self->render(text => 'Hello World!'); |
|
163 |
}; |
|
164 | ||
165 |
app->start; |
|
166 | ||
167 |
Response content is often generated by actions with |
|
168 |
L<Mojolicious::Controller/"render">, but more about that later. |
|
169 | ||
170 |
=head2 GET/POST parameters |
|
171 | ||
172 |
All GET and POST parameters sent with the request are accessible via |
|
173 |
L<Mojolicious::Controller/"param">. |
|
174 | ||
175 |
use Mojolicious::Lite; |
|
176 | ||
177 |
# /foo?user=sri |
|
178 |
get '/foo' => sub { |
|
179 |
my $self = shift; |
|
180 |
my $user = $self->param('user'); |
|
181 |
$self->render(text => "Hello $user."); |
|
182 |
}; |
|
183 | ||
184 |
app->start; |
|
185 | ||
186 |
=head2 Stash and templates |
|
187 | ||
188 |
The L<Mojolicious::Controller/"stash"> is used to pass data to templates, |
|
189 |
which can be inlined in the C<DATA> section. |
|
190 | ||
191 |
use Mojolicious::Lite; |
|
192 | ||
193 |
# Route leading to an action that renders a template |
|
194 |
get '/bar' => sub { |
|
195 |
my $self = shift; |
|
196 |
$self->stash(one => 23); |
|
197 |
$self->render('baz', two => 24); |
|
198 |
}; |
|
199 | ||
200 |
app->start; |
|
201 |
__DATA__ |
|
202 | ||
203 |
@@ baz.html.ep |
|
204 |
The magic numbers are <%= $one %> and <%= $two %>. |
|
205 | ||
206 |
For more information about templates see also |
|
207 |
L<Mojolicious::Guides::Rendering/"Embedded Perl">. |
|
208 | ||
209 |
=head2 HTTP |
|
210 | ||
211 |
L<Mojolicious::Controller/"req"> and L<Mojolicious::Controller/"res"> give you |
|
212 |
full access to all HTTP features and information. |
|
213 | ||
214 |
use Mojolicious::Lite; |
|
215 | ||
216 |
# Access request information |
|
217 |
get '/agent' => sub { |
|
218 |
my $self = shift; |
|
219 |
my $host = $self->req->url->to_abs->host; |
|
220 |
my $ua = $self->req->headers->user_agent; |
|
221 |
$self->render(text => "Request by $ua reached $host."); |
|
222 |
}; |
|
223 | ||
224 |
# Echo the request body and send custom header with response |
|
225 |
get '/echo' => sub { |
|
226 |
my $self = shift; |
|
227 |
$self->res->headers->header('X-Bender' => 'Bite my shiny metal ass!'); |
|
228 |
$self->render(data => $self->req->body); |
|
229 |
}; |
|
230 | ||
231 |
app->start; |
|
232 | ||
233 |
=head2 Route names |
|
234 | ||
235 |
All routes can have a name associated with them, this allows automatic |
|
236 |
template detection and back referencing with |
|
237 |
L<Mojolicious::Controller/"url_for"> as well as many helpers like |
|
238 |
L<Mojolicious::Plugin::TagHelpers/"link_to">. Nameless routes get an |
|
239 |
automatically generated one assigned that is simply equal to the route itself |
|
240 |
without non-word characters. |
|
241 | ||
242 |
use Mojolicious::Lite; |
|
243 | ||
244 |
# Render the template "index.html.ep" |
|
245 |
get '/' => sub { |
|
246 |
my $self = shift; |
|
247 |
$self->render; |
|
248 |
} => 'index'; |
|
249 | ||
250 |
# Render the template "hello.html.ep" |
|
251 |
get '/hello'; |
|
252 | ||
253 |
app->start; |
|
254 |
__DATA__ |
|
255 | ||
256 |
@@ index.html.ep |
|
257 |
<%= link_to Hello => 'hello' %>. |
|
258 |
<%= link_to Reload => 'index' %>. |
|
259 | ||
260 |
@@ hello.html.ep |
|
261 |
Hello World! |
|
262 | ||
263 |
=head2 Layouts |
|
264 | ||
265 |
Templates can have layouts too, you just select one with the helper |
|
266 |
L<Mojolicious::Plugin::DefaultHelpers/"layout"> and place the result of the |
|
267 |
current template with the helper |
|
268 |
L<Mojolicious::Plugin::DefaultHelpers/"content">. |
|
269 | ||
270 |
use Mojolicious::Lite; |
|
271 | ||
272 |
get '/with_layout'; |
|
273 | ||
274 |
app->start; |
|
275 |
__DATA__ |
|
276 | ||
277 |
@@ with_layout.html.ep |
|
278 |
% title 'Green'; |
|
279 |
% layout 'green'; |
|
280 |
Hello World! |
|
281 | ||
282 |
@@ layouts/green.html.ep |
|
283 |
<!DOCTYPE html> |
|
284 |
<html> |
|
285 |
<head><title><%= title %></title></head> |
|
286 |
<body><%= content %></body> |
|
287 |
</html> |
|
288 | ||
289 |
The stash or helpers like L<Mojolicious::Plugin::DefaultHelpers/"title"> can |
|
290 |
be used to pass additional data to the layout. |
|
291 | ||
292 |
=head2 Blocks |
|
293 | ||
294 |
Template blocks can be used like normal Perl functions and are always |
|
295 |
delimited by the C<begin> and C<end> keywords. |
|
296 | ||
297 |
use Mojolicious::Lite; |
|
298 | ||
299 |
get '/with_block' => 'block'; |
|
300 | ||
301 |
app->start; |
|
302 |
__DATA__ |
|
303 | ||
304 |
@@ block.html.ep |
|
305 |
% my $link = begin |
|
306 |
% my ($url, $name) = @_; |
|
307 |
Try <%= link_to $url => begin %><%= $name %><% end %>. |
|
308 |
% end |
|
309 |
<!DOCTYPE html> |
|
310 |
<html> |
|
311 |
<head><title>Sebastians frameworks</title></head> |
|
312 |
<body> |
|
313 |
%= $link->('http://mojolicio.us', 'Mojolicious') |
|
314 |
%= $link->('http://catalystframework.org', 'Catalyst') |
|
315 |
</body> |
|
316 |
</html> |
|
317 | ||
318 |
=head2 Captured content |
|
319 | ||
320 |
The helper L<Mojolicious::Plugin::DefaultHelpers/"content_for"> can be used to |
|
321 |
pass around blocks of captured content. |
|
322 | ||
323 |
use Mojolicious::Lite; |
|
324 | ||
325 |
get '/captured'; |
|
326 | ||
327 |
app->start; |
|
328 |
__DATA__ |
|
329 | ||
330 |
@@ captured.html.ep |
|
331 |
% layout 'blue', title => 'Green'; |
|
332 |
% content_for header => begin |
|
333 |
<meta http-equiv="Pragma" content="no-cache"> |
|
334 |
% end |
|
335 |
Hello World! |
|
336 |
% content_for header => begin |
|
337 |
<meta http-equiv="Expires" content="-1"> |
|
338 |
% end |
|
339 | ||
340 |
@@ layouts/blue.html.ep |
|
341 |
<!DOCTYPE html> |
|
342 |
<html> |
|
343 |
<head> |
|
344 |
<title><%= title %></title> |
|
345 |
%= content_for 'header' |
|
346 |
</head> |
|
347 |
<body><%= content %></body> |
|
348 |
</html> |
|
349 | ||
350 |
=head2 Helpers |
|
351 | ||
352 |
You can also extend L<Mojolicious> with your own helpers, a list of all |
|
353 |
built-in ones can be found in L<Mojolicious::Plugin::DefaultHelpers> and |
|
354 |
L<Mojolicious::Plugin::TagHelpers>. |
|
355 | ||
356 |
use Mojolicious::Lite; |
|
357 | ||
358 |
# A helper to identify visitors |
|
359 |
helper whois => sub { |
|
360 |
my $self = shift; |
|
361 |
my $agent = $self->req->headers->user_agent || 'Anonymous'; |
|
362 |
my $ip = $self->tx->remote_address; |
|
363 |
return "$agent ($ip)"; |
|
364 |
}; |
|
365 | ||
366 |
# Use helper in action and template |
|
367 |
get '/secret' => sub { |
|
368 |
my $self = shift; |
|
369 |
my $user = $self->whois; |
|
370 |
$self->app->log->debug("Request from $user."); |
|
371 |
}; |
|
372 | ||
373 |
app->start; |
|
374 |
__DATA__ |
|
375 | ||
376 |
@@ secret.html.ep |
|
377 |
We know who you are <%= whois %>. |
|
378 | ||
379 |
=head2 Placeholders |
|
380 | ||
381 |
Route placeholders allow capturing parts of a request path until a C</> or |
|
382 |
C<.> separator occurs, results are accessible via |
|
383 |
L<Mojolicious::Controller/"stash"> and L<Mojolicious::Controller/"param">. |
|
384 | ||
385 |
use Mojolicious::Lite; |
|
386 | ||
387 |
# /foo/test |
|
388 |
# /foo/test123 |
|
389 |
get '/foo/:bar' => sub { |
|
390 |
my $self = shift; |
|
391 |
my $bar = $self->stash('bar'); |
|
392 |
$self->render(text => "Our :bar placeholder matched $bar"); |
|
393 |
}; |
|
394 | ||
395 |
# /testsomething/foo |
|
396 |
# /test123something/foo |
|
397 |
get '/(:bar)something/foo' => sub { |
|
398 |
my $self = shift; |
|
399 |
my $bar = $self->param('bar'); |
|
400 |
$self->render(text => "Our :bar placeholder matched $bar"); |
|
401 |
}; |
|
402 | ||
403 |
app->start; |
|
404 | ||
405 |
=head2 Relaxed Placeholders |
|
406 | ||
407 |
Relaxed placeholders allow matching of everything until a C</> occurs. |
|
408 | ||
409 |
use Mojolicious::Lite; |
|
410 | ||
411 |
# /test/hello |
|
412 |
# /test123/hello |
|
413 |
# /test.123/hello |
|
414 |
get '/#you/hello' => 'groovy'; |
|
415 | ||
416 |
app->start; |
|
417 |
__DATA__ |
|
418 | ||
419 |
@@ groovy.html.ep |
|
420 |
Your name is <%= $you %>. |
|
421 | ||
422 |
=head2 Wildcard placeholders |
|
423 | ||
424 |
Wildcard placeholders allow matching absolutely everything, including C</> and |
|
425 |
C<.>. |
|
426 | ||
427 |
use Mojolicious::Lite; |
|
428 | ||
429 |
# /hello/test |
|
430 |
# /hello/test123 |
|
431 |
# /hello/test.123/test/123 |
|
432 |
get '/hello/*you' => 'groovy'; |
|
433 | ||
434 |
app->start; |
|
435 |
__DATA__ |
|
436 | ||
437 |
@@ groovy.html.ep |
|
438 |
Your name is <%= $you %>. |
|
439 | ||
440 |
=head2 HTTP methods |
|
441 | ||
442 |
Routes can be restricted to specific request methods with different keywords. |
|
443 | ||
444 |
use Mojolicious::Lite; |
|
445 | ||
446 |
# GET /hello |
|
447 |
get '/hello' => sub { |
|
448 |
my $self = shift; |
|
449 |
$self->render(text => 'Hello World!'); |
|
450 |
}; |
|
451 | ||
452 |
# PUT /hello |
|
453 |
put '/hello' => sub { |
|
454 |
my $self = shift; |
|
455 |
my $size = length $self->req->body; |
|
456 |
$self->render(text => "You uploaded $size bytes to /hello."); |
|
457 |
}; |
|
458 | ||
459 |
# GET|POST|PATCH /bye |
|
460 |
any [qw(GET POST PATCH)] => '/bye' => sub { |
|
461 |
my $self = shift; |
|
462 |
$self->render(text => 'Bye World!'); |
|
463 |
}; |
|
464 | ||
465 |
# * /whatever |
|
466 |
any '/whatever' => sub { |
|
467 |
my $self = shift; |
|
468 |
my $method = $self->req->method; |
|
469 |
$self->render(text => "You called /whatever with $method."); |
|
470 |
}; |
|
471 | ||
472 |
app->start; |
|
473 | ||
474 |
=head2 Optional placeholders |
|
475 | ||
476 |
All placeholders require a value, but by assigning them default values you can |
|
477 |
make capturing optional. |
|
478 | ||
479 |
use Mojolicious::Lite; |
|
480 | ||
481 |
# /hello |
|
482 |
# /hello/Sara |
|
483 |
get '/hello/:name' => {name => 'Sebastian'} => sub { |
|
484 |
my $self = shift; |
|
485 |
$self->render('groovy', format => 'txt'); |
|
486 |
}; |
|
487 | ||
488 |
app->start; |
|
489 |
__DATA__ |
|
490 | ||
491 |
@@ groovy.txt.ep |
|
492 |
My name is <%= $name %>. |
|
493 | ||
494 |
=head2 Restrictive placeholders |
|
495 | ||
496 |
The easiest way to make placeholders more restrictive are alternatives, you |
|
497 |
just make a list of possible values. |
|
498 | ||
499 |
use Mojolicious::Lite; |
|
500 | ||
501 |
# /test |
|
502 |
# /123 |
|
503 |
any '/:foo' => [foo => [qw(test 123)]] => sub { |
|
504 |
my $self = shift; |
|
505 |
my $foo = $self->param('foo'); |
|
506 |
$self->render(text => "Our :foo placeholder matched $foo"); |
|
507 |
}; |
|
508 | ||
509 |
app->start; |
|
510 | ||
511 |
All placeholders get compiled to a regular expression internally, this process |
|
512 |
can also be easily customized. |
|
513 | ||
514 |
use Mojolicious::Lite; |
|
515 | ||
516 |
# /1 |
|
517 |
# /123 |
|
518 |
any '/:bar' => [bar => qr/\d+/] => sub { |
|
519 |
my $self = shift; |
|
520 |
my $bar = $self->param('bar'); |
|
521 |
$self->render(text => "Our :bar placeholder matched $bar"); |
|
522 |
}; |
|
523 | ||
524 |
app->start; |
|
525 | ||
526 |
Just make sure not to use C<^> and C<$> or capturing groups C<(...)>, because |
|
527 |
placeholders become part of a larger regular expression internally, C<(?:...)> |
|
528 |
is fine though. |
|
529 | ||
530 |
=head2 Under |
|
531 | ||
532 |
Authentication and code shared between multiple routes can be realized easily |
|
533 |
with bridge routes generated by the L</"under"> statement. All following |
|
534 |
routes are only evaluated if the callback returned a true value. |
|
535 | ||
536 |
use Mojolicious::Lite; |
|
537 | ||
538 |
# Authenticate based on name parameter |
|
539 |
under sub { |
|
540 |
my $self = shift; |
|
541 | ||
542 |
# Authenticated |
|
543 |
my $name = $self->param('name') || ''; |
|
544 |
return 1 if $name eq 'Bender'; |
|
545 | ||
546 |
# Not authenticated |
|
547 |
$self->render('denied'); |
|
548 |
return undef; |
|
549 |
}; |
|
550 | ||
551 |
# Only reached when authenticated |
|
552 |
get '/' => 'index'; |
|
553 | ||
554 |
app->start; |
|
555 |
__DATA__ |
|
556 | ||
557 |
@@ denied.html.ep |
|
558 |
You are not Bender, permission denied. |
|
559 | ||
560 |
@@ index.html.ep |
|
561 |
Hi Bender. |
|
562 | ||
563 |
Prefixing multiple routes is another good use for L</"under">. |
|
564 | ||
565 |
use Mojolicious::Lite; |
|
566 | ||
567 |
# /foo |
|
568 |
under '/foo'; |
|
569 | ||
570 |
# /foo/bar |
|
571 |
get '/bar' => {text => 'foo bar'}; |
|
572 | ||
573 |
# /foo/baz |
|
574 |
get '/baz' => {text => 'foo baz'}; |
|
575 | ||
576 |
# / (reset) |
|
577 |
under '/' => {msg => 'whatever'}; |
|
578 | ||
579 |
# /bar |
|
580 |
get '/bar' => {inline => '<%= $msg %> works'}; |
|
581 | ||
582 |
app->start; |
|
583 | ||
584 |
You can also L</"group"> related routes, which allows nesting of multiple |
|
585 |
L</"under"> statements. |
|
586 | ||
587 |
use Mojolicious::Lite; |
|
588 | ||
589 |
# Global logic shared by all routes |
|
590 |
under sub { |
|
591 |
my $self = shift; |
|
592 |
return 1 if $self->req->headers->header('X-Bender'); |
|
593 |
$self->render(text => "You're not Bender."); |
|
594 |
return undef; |
|
595 |
}; |
|
596 | ||
597 |
# Admin section |
|
598 |
group { |
|
599 | ||
600 |
# Local logic shared only by routes in this group |
|
601 |
under '/admin' => sub { |
|
602 |
my $self = shift; |
|
603 |
return 1 if $self->req->headers->header('X-Awesome'); |
|
604 |
$self->render(text => "You're not awesome enough."); |
|
605 |
return undef; |
|
606 |
}; |
|
607 | ||
608 |
# GET /admin/dashboard |
|
609 |
get '/dashboard' => {text => 'Nothing to see here yet.'}; |
|
610 |
}; |
|
611 | ||
612 |
# GET /welcome |
|
613 |
get '/welcome' => {text => 'Hi Bender.'}; |
|
614 | ||
615 |
app->start; |
|
616 | ||
617 |
=head2 Formats |
|
618 | ||
619 |
Formats can be automatically detected by looking at file extensions. |
|
620 | ||
621 |
use Mojolicious::Lite; |
|
622 | ||
623 |
# /detection.html |
|
624 |
# /detection.txt |
|
625 |
get '/detection' => sub { |
|
626 |
my $self = shift; |
|
627 |
$self->render('detected'); |
|
628 |
}; |
|
629 | ||
630 |
app->start; |
|
631 |
__DATA__ |
|
632 | ||
633 |
@@ detected.html.ep |
|
634 |
<!DOCTYPE html> |
|
635 |
<html> |
|
636 |
<head><title>Detected</title></head> |
|
637 |
<body>HTML was detected.</body> |
|
638 |
</html> |
|
639 | ||
640 |
@@ detected.txt.ep |
|
641 |
TXT was detected. |
|
642 | ||
643 |
Restrictive placeholders can also be used. |
|
644 | ||
645 |
use Mojolicious::Lite; |
|
646 | ||
647 |
# /hello.json |
|
648 |
# /hello.txt |
|
649 |
get '/hello' => [format => [qw(json txt)]] => sub { |
|
650 |
my $self = shift; |
|
651 |
return $self->render(json => {hello => 'world'}) |
|
652 |
if $self->stash('format') eq 'json'; |
|
653 |
$self->render(text => 'hello world'); |
|
654 |
}; |
|
655 | ||
656 |
app->start; |
|
657 | ||
658 |
Or you can just disable format detection. |
|
659 | ||
660 |
use Mojolicious::Lite; |
|
661 | ||
662 |
# /hello |
|
663 |
get '/hello' => [format => 0] => {text => 'No format detection.'}; |
|
664 | ||
665 |
# Disable detection and allow the following routes selective re-enabling |
|
666 |
under [format => 0]; |
|
667 | ||
668 |
# /foo |
|
669 |
get '/foo' => {text => 'No format detection again.'}; |
|
670 | ||
671 |
# /bar.txt |
|
672 |
get '/bar' => [format => 'txt'] => {text => ' Just one format.'}; |
|
673 | ||
674 |
app->start; |
|
675 | ||
676 |
=head2 Content negotiation |
|
677 | ||
678 |
For resources with different representations and that require truly C<RESTful> |
|
679 |
content negotiation you can also use L<Mojolicious::Controller/"respond_to">. |
|
680 | ||
681 |
use Mojolicious::Lite; |
|
682 | ||
683 |
# /hello (Accept: application/json) |
|
684 |
# /hello (Accept: application/xml) |
|
685 |
# /hello.json |
|
686 |
# /hello.xml |
|
687 |
# /hello?format=json |
|
688 |
# /hello?format=xml |
|
689 |
get '/hello' => sub { |
|
690 |
my $self = shift; |
|
691 |
$self->respond_to( |
|
692 |
json => {json => {hello => 'world'}}, |
|
693 |
xml => {text => '<hello>world</hello>'}, |
|
694 |
any => {data => '', status => 204} |
|
695 |
); |
|
696 |
}; |
|
697 | ||
698 |
app->start; |
|
699 | ||
700 |
MIME type mappings can be extended or changed easily with |
|
701 |
L<Mojolicious/"types">. |
|
702 | ||
703 |
app->types->type(rdf => 'application/rdf+xml'); |
|
704 | ||
705 |
=head2 Static files |
|
706 | ||
707 |
Similar to templates, but with only a single file extension and optional |
|
708 |
Base64 encoding, static files can be inlined in the C<DATA> section and are |
|
709 |
served automatically. |
|
710 | ||
711 |
use Mojolicious::Lite; |
|
712 | ||
713 |
app->start; |
|
714 |
__DATA__ |
|
715 | ||
716 |
@@ something.js |
|
717 |
alert('hello!'); |
|
718 | ||
719 |
@@ test.txt (base64) |
|
720 |
dGVzdCAxMjMKbGFsYWxh |
|
721 | ||
722 |
External static files are not limited to a single file extension and will be |
|
723 |
served automatically from a C<public> directory if it exists. |
|
724 | ||
725 |
$ mkdir public |
|
726 |
$ mv something.js public/something.js |
|
727 |
$ mv mojolicious.tar.gz public/mojolicious.tar.gz |
|
728 | ||
729 |
Both have a higher precedence than routes. |
|
730 | ||
731 |
=head2 External templates |
|
732 | ||
733 |
External templates will be searched by the renderer in a C<templates> |
|
734 |
directory if it exists. |
|
735 | ||
736 |
use Mojolicious::Lite; |
|
737 | ||
738 |
# Render template "templates/foo/bar.html.ep" |
|
739 |
any '/external' => sub { |
|
740 |
my $self = shift; |
|
741 |
$self->render('foo/bar'); |
|
742 |
}; |
|
743 | ||
744 |
app->start; |
|
745 | ||
746 |
=head2 Conditions |
|
747 | ||
748 |
Conditions such as C<agent> and C<host> from |
|
749 |
L<Mojolicious::Plugin::HeaderCondition> allow even more powerful route |
|
750 |
constructs. |
|
751 | ||
752 |
use Mojolicious::Lite; |
|
753 | ||
754 |
# Firefox |
|
755 |
get '/foo' => (agent => qr/Firefox/) => sub { |
|
756 |
my $self = shift; |
|
757 |
$self->render(text => 'Congratulations, you are using a cool browser.'); |
|
758 |
}; |
|
759 | ||
760 |
# Internet Explorer |
|
761 |
get '/foo' => (agent => qr/Internet Explorer/) => sub { |
|
762 |
my $self = shift; |
|
763 |
$self->render(text => 'Dude, you really need to upgrade to Firefox.'); |
|
764 |
}; |
|
765 | ||
766 |
# http://mojolicio.us/bar |
|
767 |
get '/bar' => (host => 'mojolicio.us') => sub { |
|
768 |
my $self = shift; |
|
769 |
$self->render(text => 'Hello Mojolicious.'); |
|
770 |
}; |
|
771 | ||
772 |
app->start; |
|
773 | ||
774 |
=head2 Sessions |
|
775 | ||
776 |
Signed cookie based sessions just work out of the box as soon as you start |
|
777 |
using them through the helper |
|
778 |
L<Mojolicious::Plugin::DefaultHelpers/"session">, just be aware that all |
|
779 |
session data gets serialized with L<Mojo::JSON>. |
|
780 | ||
781 |
use Mojolicious::Lite; |
|
782 | ||
783 |
# Access session data in action and template |
|
784 |
get '/counter' => sub { |
|
785 |
my $self = shift; |
|
786 |
$self->session->{counter}++; |
|
787 |
}; |
|
788 | ||
789 |
app->start; |
|
790 |
__DATA__ |
|
791 | ||
792 |
@@ counter.html.ep |
|
793 |
Counter: <%= session 'counter' %> |
|
794 | ||
795 |
Note that you should use a custom L<Mojolicious/"secret"> to make signed |
|
796 |
cookies really secure. |
|
797 | ||
798 |
app->secret('My secret passphrase here'); |
|
799 | ||
800 |
=head2 File uploads |
|
801 | ||
802 |
All files uploaded via C<multipart/form-data> request are automatically |
|
803 |
available as L<Mojo::Upload> objects. And you don't have to worry about memory |
|
804 |
usage, because all files above C<250KB> will be automatically streamed into a |
|
805 |
temporary file. |
|
806 | ||
807 |
use Mojolicious::Lite; |
|
808 | ||
809 |
# Upload form in DATA section |
|
810 |
get '/' => 'form'; |
|
811 | ||
812 |
# Multipart upload handler |
|
813 |
post '/upload' => sub { |
|
814 |
my $self = shift; |
|
815 | ||
816 |
# Check file size |
|
817 |
return $self->render(text => 'File is too big.', status => 200) |
|
818 |
if $self->req->is_limit_exceeded; |
|
819 | ||
820 |
# Process uploaded file |
|
821 |
return $self->redirect_to('form') |
|
822 |
unless my $example = $self->param('example'); |
|
823 |
my $size = $example->size; |
|
824 |
my $name = $example->filename; |
|
825 |
$self->render(text => "Thanks for uploading $size byte file $name."); |
|
826 |
}; |
|
827 | ||
828 |
app->start; |
|
829 |
__DATA__ |
|
830 | ||
831 |
@@ form.html.ep |
|
832 |
<!DOCTYPE html> |
|
833 |
<html> |
|
834 |
<head><title>Upload</title></head> |
|
835 |
<body> |
|
836 |
%= form_for upload => (enctype => 'multipart/form-data') => begin |
|
837 |
%= file_field 'example' |
|
838 |
%= submit_button 'Upload' |
|
839 |
% end |
|
840 |
</body> |
|
841 |
</html> |
|
842 | ||
843 |
To protect you from excessively large files there is also a limit of C<10MB> |
|
844 |
by default, which you can tweak with the MOJO_MAX_MESSAGE_SIZE environment |
|
845 |
variable. |
|
846 | ||
847 |
# Increase limit to 1GB |
|
848 |
$ENV{MOJO_MAX_MESSAGE_SIZE} = 1073741824; |
|
849 | ||
850 |
=head2 User agent |
|
851 | ||
852 |
With L<Mojo::UserAgent>, which is available through the helper |
|
853 |
L<Mojolicious::Plugin::DefaultHelpers/"ua">, there's a full featured HTTP and |
|
854 |
WebSocket user agent built right in. Especially in combination with |
|
855 |
L<Mojo::JSON> and L<Mojo::DOM> this can be a very powerful tool. |
|
856 | ||
857 |
use Mojolicious::Lite; |
|
858 | ||
859 |
# Blocking |
|
860 |
get '/headers' => sub { |
|
861 |
my $self = shift; |
|
862 |
my $url = $self->param('url') || 'http://mojolicio.us'; |
|
863 |
my $dom = $self->ua->get($url)->res->dom; |
|
864 |
$self->render(json => [$dom->find('h1, h2, h3')->text->each]); |
|
865 |
}; |
|
866 | ||
867 |
# Non-blocking |
|
868 |
get '/title' => sub { |
|
869 |
my $self = shift; |
|
870 |
$self->ua->get('mojolicio.us' => sub { |
|
871 |
my ($ua, $tx) = @_; |
|
872 |
$self->render(data => $tx->res->dom->at('title')->text); |
|
873 |
}); |
|
874 |
}; |
|
875 | ||
876 |
# Parallel non-blocking |
|
877 |
get '/titles' => sub { |
|
878 |
my $self = shift; |
|
879 |
my $delay = Mojo::IOLoop->delay(sub { |
|
880 |
my ($delay, @titles) = @_; |
|
881 |
$self->render(json => \@titles); |
|
882 |
}); |
|
883 |
for my $url ('http://mojolicio.us', 'https://metacpan.org') { |
|
884 |
my $end = $delay->begin(0); |
|
885 |
$self->ua->get($url => sub { |
|
886 |
my ($ua, $tx) = @_; |
|
887 |
$end->($tx->res->dom->html->head->title->text); |
|
888 |
}); |
|
889 |
} |
|
890 |
}; |
|
891 | ||
892 |
app->start; |
|
893 | ||
894 |
For more information about the user agent see also |
|
895 |
L<Mojolicious::Guides::Cookbook/"USER AGENT">. |
|
896 | ||
897 |
=head2 WebSockets |
|
898 | ||
899 |
WebSocket applications have never been this simple before. Just receive |
|
900 |
messages by subscribing to events such as |
|
901 |
L<Mojo::Transaction::WebSocket/"json"> with L<Mojolicious::Controller/"on"> |
|
902 |
and return them with L<Mojolicious::Controller/"send">. |
|
903 | ||
904 |
use Mojolicious::Lite; |
|
905 | ||
906 |
websocket '/echo' => sub { |
|
907 |
my $self = shift; |
|
908 |
$self->on(json => sub { |
|
909 |
my ($self, $hash) = @_; |
|
910 |
$hash->{msg} = "echo: $hash->{msg}"; |
|
911 |
$self->send({json => $hash}); |
|
912 |
}); |
|
913 |
}; |
|
914 | ||
915 |
get '/' => 'index'; |
|
916 | ||
917 |
app->start; |
|
918 |
__DATA__ |
|
919 | ||
920 |
@@ index.html.ep |
|
921 |
<!DOCTYPE html> |
|
922 |
<html> |
|
923 |
<head> |
|
924 |
<title>Echo</title> |
|
925 |
%= javascript begin |
|
926 |
var ws = new WebSocket('<%= url_for('echo')->to_abs %>'); |
|
927 |
ws.onmessage = function (event) { |
|
928 |
document.body.innerHTML += JSON.parse(event.data).msg; |
|
929 |
}; |
|
930 |
ws.onopen = function (event) { |
|
931 |
ws.send(JSON.stringify({msg: 'I ♥ Mojolicious!'})); |
|
932 |
}; |
|
933 |
% end |
|
934 |
</head> |
|
935 |
</html> |
|
936 | ||
937 |
For more information about real-time web features see also |
|
938 |
L<Mojolicious::Guides::Cookbook/"REAL-TIME WEB">. |
|
939 | ||
940 |
=head2 Mode |
|
941 | ||
942 |
You can use the L<Mojo::Log> object from L<Mojo/"log"> to portably collect |
|
943 |
debug messages and automatically disable them later in a production setup by |
|
944 |
changing the L<Mojolicious> operating mode, which can also be retrieved from |
|
945 |
the attribute L<Mojolicious/"mode">. |
|
946 | ||
947 |
use Mojolicious::Lite; |
|
948 | ||
949 |
# Prepare mode specific message during startup |
|
950 |
my $msg = app->mode eq 'development' ? 'Development!' : 'Something else!'; |
|
951 | ||
952 |
get '/' => sub { |
|
953 |
my $self = shift; |
|
954 |
$self->app->log->debug('Rendering mode specific message.'); |
|
955 |
$self->render(text => $msg); |
|
956 |
}; |
|
957 | ||
958 |
app->log->debug('Starting application.'); |
|
959 |
app->start; |
|
960 | ||
961 |
The default operating mode will usually be C<development> and can be changed |
|
962 |
with command line options or the MOJO_MODE and PLACK_ENV environment |
|
963 |
variables. A mode other than C<development> will raise the log level from |
|
964 |
C<debug> to C<info>. |
|
965 | ||
966 |
$ ./myapp.pl daemon -m production |
|
967 | ||
968 |
All messages will be written to C<STDERR> or a C<log/$mode.log> file if a |
|
969 |
C<log> directory exists. |
|
970 | ||
971 |
$ mkdir log |
|
972 | ||
973 |
Mode changes also affect a few other aspects of the framework, such as mode |
|
974 |
specific C<exception> and C<not_found> templates. |
|
975 | ||
976 |
=head2 Testing |
|
977 | ||
978 |
Testing your application is as easy as creating a C<t> directory and filling |
|
979 |
it with normal Perl unit tests, which can be a lot of fun thanks to |
|
980 |
L<Test::Mojo>. |
|
981 | ||
982 |
use Test::More; |
|
983 |
use Test::Mojo; |
|
984 | ||
985 |
use FindBin; |
|
986 |
require "$FindBin::Bin/../myapp.pl"; |
|
987 | ||
988 |
my $t = Test::Mojo->new; |
|
989 |
$t->get_ok('/')->status_is(200)->content_like(qr/Funky/); |
|
990 | ||
991 |
done_testing(); |
|
992 | ||
993 |
Run all unit tests with the C<test> command. |
|
994 | ||
995 |
$ ./myapp.pl test |
|
996 |
$ ./myapp.pl test -v |
|
997 | ||
998 |
=head2 More |
|
999 | ||
1000 |
You can continue with L<Mojolicious::Guides> now, and don't forget to have |
|
1001 |
fun! |
|
1002 | ||
1003 |
=head1 FUNCTIONS |
|
1004 | ||
1005 |
L<Mojolicious::Lite> implements the following functions. |
|
1006 | ||
1007 |
=head2 any |
|
1008 | ||
1009 |
my $route = any '/:foo' => sub {...}; |
|
1010 |
my $route = any [qw(GET POST)] => '/:foo' => sub {...}; |
|
1011 | ||
1012 |
Generate route with L<Mojolicious::Routes::Route/"any">, matching any of the |
|
1013 |
listed HTTP request methods or all. See also the tutorial above for more |
|
1014 |
argument variations. |
|
1015 | ||
1016 |
=head2 app |
|
1017 | ||
1018 |
my $app = app; |
|
1019 | ||
1020 |
The L<Mojolicious::Lite> application. |
|
1021 | ||
1022 |
=head2 del |
|
1023 | ||
1024 |
my $route = del '/:foo' => sub {...}; |
|
1025 | ||
1026 |
Generate route with L<Mojolicious::Routes::Route/"delete">, matching only |
|
1027 |
DELETE requests. See also the tutorial above for more argument variations. |
|
1028 | ||
1029 |
=head2 get |
|
1030 | ||
1031 |
my $route = get '/:foo' => sub {...}; |
|
1032 | ||
1033 |
Generate route with L<Mojolicious::Routes::Route/"get">, matching only GET |
|
1034 |
requests. See also the tutorial above for more argument variations. |
|
1035 | ||
1036 |
=head2 group |
|
1037 | ||
1038 |
group {...}; |
|
1039 | ||
1040 |
Start a new route group. |
|
1041 | ||
1042 |
=head2 helper |
|
1043 | ||
1044 |
helper foo => sub {...}; |
|
1045 | ||
1046 |
Add a new helper with L<Mojolicious/"helper">. |
|
1047 | ||
1048 |
=head2 hook |
|
1049 | ||
1050 |
hook after_dispatch => sub {...}; |
|
1051 | ||
1052 |
Share code with L<Mojolicious/"hook">. |
|
1053 | ||
1054 |
=head2 options |
|
1055 | ||
1056 |
my $route = options '/:foo' => sub {...}; |
|
1057 | ||
1058 |
Generate route with L<Mojolicious::Routes::Route/"options">, matching only |
|
1059 |
OPTIONS requests. See also the tutorial above for more argument |
|
1060 |
variations. |
|
1061 | ||
1062 |
=head2 patch |
|
1063 | ||
1064 |
my $route = patch '/:foo' => sub {...}; |
|
1065 | ||
1066 |
Generate route with L<Mojolicious::Routes::Route/"patch">, matching only |
|
1067 |
PATCH requests. See also the tutorial above for more argument variations. |
|
1068 | ||
1069 |
=head2 plugin |
|
1070 | ||
1071 |
plugin SomePlugin => {foo => 23}; |
|
1072 | ||
1073 |
Load a plugin with L<Mojolicious/"plugin">. |
|
1074 | ||
1075 |
=head2 post |
|
1076 | ||
1077 |
my $route = post '/:foo' => sub {...}; |
|
1078 | ||
1079 |
Generate route with L<Mojolicious::Routes::Route/"post">, matching only |
|
1080 |
POST requests. See also the tutorial above for more argument variations. |
|
1081 | ||
1082 |
=head2 put |
|
1083 | ||
1084 |
my $route = put '/:foo' => sub {...}; |
|
1085 | ||
1086 |
Generate route with L<Mojolicious::Routes::Route/"put">, matching only PUT |
|
1087 |
requests. See also the tutorial above for more argument variations. |
|
1088 | ||
1089 |
=head2 under |
|
1090 | ||
1091 |
my $bridge = under sub {...}; |
|
1092 |
my $bridge = under '/:foo'; |
|
1093 | ||
1094 |
Generate bridge route with L<Mojolicious::Routes::Route/"under">, to which all |
|
1095 |
following routes are automatically appended. See also the tutorial above for |
|
1096 |
more argument variations. |
|
1097 | ||
1098 |
=head2 websocket |
|
1099 | ||
1100 |
my $route = websocket '/:foo' => sub {...}; |
|
1101 | ||
1102 |
Generate route with L<Mojolicious::Routes::Route/"websocket">, matching only |
|
1103 |
WebSocket handshakes. See also the tutorial above for more argument |
|
1104 |
variations. |
|
1105 | ||
1106 |
=head1 ATTRIBUTES |
|
1107 | ||
1108 |
L<Mojolicious::Lite> inherits all attributes from L<Mojolicious>. |
|
1109 | ||
1110 |
=head1 METHODS |
|
1111 | ||
1112 |
L<Mojolicious::Lite> inherits all methods from L<Mojolicious>. |
|
1113 | ||
1114 |
=head1 SEE ALSO |
|
1115 | ||
1116 |
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
1117 | ||
1118 |
=cut |