1Mojolicious::Guides::TuUtsoerriaClo(n3t)ributed Perl DocMuomjeonltiactiioouns::Guides::Tutorial(3)
2
3
4
6 Mojolicious::Guides::Tutorial - Get started with Mojolicious
7
9 A quick example-driven introduction to the wonders of
10 Mojolicious::Lite. Almost everything you'll learn here also applies to
11 full Mojolicious applications.
12
13 This is only the first of the Mojolicious::Guides. Other guides delve
14 deeper into topics like growing a Mojolicious::Lite prototype into a
15 well-structured Mojolicious application, routing, rendering and more.
16 It is highly encouraged that readers continue on to the remaining
17 guides after reading this one.
18
19 Hello World
20 A simple Hello World application can look like this, strict, warnings,
21 utf8 and Perl 5.16 features are automatically enabled and a few
22 functions imported, when you use Mojolicious::Lite, turning your script
23 into a full featured web application.
24
25 #!/usr/bin/env perl
26 use Mojolicious::Lite;
27
28 get '/' => sub {
29 my $c = shift;
30 $c->render(text => 'Hello World!');
31 };
32
33 app->start;
34
35 With Mojolicious::Command::Author::generate::lite_app there is also a
36 helper command to generate a small example application.
37
38 $ mojo generate lite-app myapp.pl
39
40 Commands
41 Many different commands are automatically available from the command
42 line. CGI and PSGI environments can even be detected and will usually
43 just work without commands.
44
45 $ ./myapp.pl daemon
46 Web application available at http://127.0.0.1:3000
47
48 $ ./myapp.pl daemon -l http://*:8080
49 Web application available at http://127.0.0.1:8080
50
51 $ ./myapp.pl cgi
52 ...CGI output...
53
54 $ ./myapp.pl get /
55 Hello World!
56
57 $ ./myapp.pl
58 ...List of available commands (or automatically detected environment)...
59
60 A call to "start" in Mojolicious ("app->start"), which starts the
61 command system, should be the last expression in your application,
62 because its return value can be significant.
63
64 # Use @ARGV to pick a command
65 app->start;
66
67 # Start the "daemon" command
68 app->start('daemon', '-l', 'http://*:8080');
69
70 Reloading
71 Your application will automatically reload itself if you start it with
72 the morbo development web server, so you don't have to restart the
73 server after every change.
74
75 $ morbo ./myapp.pl
76 Web application available at http://127.0.0.1:3000
77
78 For more information about how to deploy your application see also
79 "DEPLOYMENT" in Mojolicious::Guides::Cookbook.
80
81 Routes
82 Routes are basically just fancy paths that can contain different kinds
83 of placeholders and usually lead to an action, if they match the path
84 part of the request URL. The first argument passed to all actions ($c)
85 is a Mojolicious::Controller object, containing both the HTTP request
86 and response.
87
88 use Mojolicious::Lite;
89
90 # Route leading to an action that renders some text
91 get '/foo' => sub {
92 my $c = shift;
93 $c->render(text => 'Hello World!');
94 };
95
96 app->start;
97
98 Response content is often generated by actions with "render" in
99 Mojolicious::Controller, but more about that later.
100
101 GET/POST parameters
102 All "GET" and "POST" parameters sent with the request are accessible
103 via "param" in Mojolicious::Controller.
104
105 use Mojolicious::Lite;
106
107 # /foo?user=sri
108 get '/foo' => sub {
109 my $c = shift;
110 my $user = $c->param('user');
111 $c->render(text => "Hello $user.");
112 };
113
114 app->start;
115
116 Stash and templates
117 The "stash" in Mojolicious::Controller is used to pass data to
118 templates, which can be inlined in the "DATA" section. A few stash
119 values like "template", "text" and "data" are reserved and will be used
120 by "render" in Mojolicious::Controller to decide how a response should
121 be generated.
122
123 use Mojolicious::Lite;
124
125 # Route leading to an action that renders a template
126 get '/foo' => sub {
127 my $c = shift;
128 $c->stash(one => 23);
129 $c->render(template => 'magic', two => 24);
130 };
131
132 app->start;
133 __DATA__
134
135 @@ magic.html.ep
136 The magic numbers are <%= $one %> and <%= $two %>.
137
138 For more information about templates see also "Embedded Perl" in
139 Mojolicious::Guides::Rendering.
140
141 HTTP
142 "req" in Mojolicious::Controller and "res" in Mojolicious::Controller
143 give you full access to all HTTP features and information.
144
145 use Mojolicious::Lite;
146
147 # Access request information
148 get '/agent' => sub {
149 my $c = shift;
150 my $host = $c->req->url->to_abs->host;
151 my $ua = $c->req->headers->user_agent;
152 $c->render(text => "Request by $ua reached $host.");
153 };
154
155 # Echo the request body and send custom header with response
156 post '/echo' => sub {
157 my $c = shift;
158 $c->res->headers->header('X-Bender' => 'Bite my shiny metal ass!');
159 $c->render(data => $c->req->body);
160 };
161
162 app->start;
163
164 You can test the more advanced examples right from the command line
165 with Mojolicious::Command::get.
166
167 $ ./myapp.pl get -v -M POST -c 'test' /echo
168
169 JSON
170 JSON is the most commonly used data-interchange format for web
171 services. Mojolicious loves JSON and comes with the possibly fastest
172 pure-Perl implementation Mojo::JSON built right in, which is accessible
173 through "json" in Mojo::Message as well as the reserved stash value
174 "json".
175
176 use Mojolicious::Lite;
177
178 # Modify the received JSON document and return it
179 put '/reverse' => sub {
180 my $c = shift;
181 my $hash = $c->req->json;
182 $hash->{message} = reverse $hash->{message};
183 $c->render(json => $hash);
184 };
185
186 app->start;
187
188 You can send JSON documents from the command line with
189 Mojolicious::Command::get.
190
191 $ ./myapp.pl get -M PUT -c '{"message":"Hello Mojo!"}' /reverse
192
193 Built-in "exception" and "not_found" pages
194 During development you will encounter these pages whenever you make a
195 mistake, they are gorgeous and contain a lot of valuable information
196 that will aid you in debugging your application.
197
198 use Mojolicious::Lite;
199
200 # Not found (404)
201 get '/missing' => sub { shift->render(template => 'does_not_exist') };
202
203 # Exception (500)
204 get '/dies' => sub { die 'Intentional error' };
205
206 app->start;
207
208 You can even use CSS selectors with Mojolicious::Command::get to
209 extract only the information you're actually interested in.
210
211 $ ./myapp.pl get /dies '#error'
212
213 And don't worry about revealing too much information on these pages,
214 they are only available during development, and will be replaced
215 automatically with pages that don't reveal any sensitive information in
216 a production environment.
217
218 Route names
219 All routes can have a name associated with them, this allows automatic
220 template detection and backreferencing with "url_for" in
221 Mojolicious::Controller, on which many methods and helpers like
222 "link_to" in Mojolicious::Plugin::TagHelpers rely.
223
224 use Mojolicious::Lite;
225
226 # Render the template "index.html.ep"
227 get '/' => sub {
228 my $c = shift;
229 $c->render;
230 } => 'index';
231
232 # Render the template "hello.html.ep"
233 get '/hello';
234
235 app->start;
236 __DATA__
237
238 @@ index.html.ep
239 <%= link_to Hello => 'hello' %>.
240 <%= link_to Reload => 'index' %>.
241
242 @@ hello.html.ep
243 Hello World!
244
245 Nameless routes get an automatically generated one assigned that is
246 simply equal to the route itself without non-word characters.
247
248 Layouts
249 Templates can have layouts too, you just select one with the helper
250 "layout" in Mojolicious::Plugin::DefaultHelpers and place the result of
251 the current template with the helper "content" in
252 Mojolicious::Plugin::DefaultHelpers.
253
254 use Mojolicious::Lite;
255
256 get '/with_layout';
257
258 app->start;
259 __DATA__
260
261 @@ with_layout.html.ep
262 % title 'Green';
263 % layout 'green';
264 Hello World!
265
266 @@ layouts/green.html.ep
267 <!DOCTYPE html>
268 <html>
269 <head><title><%= title %></title></head>
270 <body><%= content %></body>
271 </html>
272
273 The stash or helpers like "title" in
274 Mojolicious::Plugin::DefaultHelpers can be used to pass additional data
275 to the layout.
276
277 Blocks
278 Template blocks can be used like normal Perl functions and are always
279 delimited by the "begin" and "end" keywords, they are the foundation
280 for many helpers.
281
282 use Mojolicious::Lite;
283
284 get '/with_block' => 'block';
285
286 app->start;
287 __DATA__
288
289 @@ block.html.ep
290 % my $link = begin
291 % my ($url, $name) = @_;
292 Try <%= link_to $url => begin %><%= $name %><% end %>.
293 % end
294 <!DOCTYPE html>
295 <html>
296 <head><title>Sebastians frameworks</title></head>
297 <body>
298 %= $link->('http://mojolicious.org', 'Mojolicious')
299 %= $link->('http://catalystframework.org', 'Catalyst')
300 </body>
301 </html>
302
303 Helpers
304 Helpers are little functions you can create with the keyword "helper"
305 in Mojolicious::Lite and reuse throughout your whole application, from
306 actions to templates.
307
308 use Mojolicious::Lite;
309
310 # A helper to identify visitors
311 helper whois => sub {
312 my $c = shift;
313 my $agent = $c->req->headers->user_agent || 'Anonymous';
314 my $ip = $c->tx->remote_address;
315 return "$agent ($ip)";
316 };
317
318 # Use helper in action and template
319 get '/secret' => sub {
320 my $c = shift;
321 my $user = $c->whois;
322 $c->app->log->debug("Request from $user");
323 };
324
325 app->start;
326 __DATA__
327
328 @@ secret.html.ep
329 We know who you are <%= whois %>.
330
331 A list of all built-in ones can be found in
332 Mojolicious::Plugin::DefaultHelpers and
333 Mojolicious::Plugin::TagHelpers.
334
335 Plugins
336 Plugins are application extensions that help with code sharing and
337 organization. You can load a plugin with the keyword "plugin" in
338 Mojolicious::Lite, which can omit the "Mojolicious::Plugin::" part of
339 the name, and optionally provide configuration for the plugin.
340
341 use Mojolicious::Lite;
342
343 plugin Config => {file => '/etc/myapp.conf', default => {foo => 'bar'}};
344
345 # Return configured foo value, or default if no configuration file
346 get '/foo' => sub {
347 my $c = shift;
348 my $foo = $c->app->config('foo');
349 $c->render(json => {foo => $foo});
350 };
351
352 app->start;
353
354 Mojolicious::Plugin::Config is a built-in plugin which can populate
355 "config" in Mojolicious using a config file. Plugins can also set up
356 routes, hooks, handlers, or even load other plugins. A list of built-in
357 plugins can be found at "PLUGINS" in Mojolicious::Plugins, and many
358 more are available from CPAN
359 <https://metacpan.org/search?q=Mojolicious+Plugin>.
360
361 Placeholders
362 Route placeholders allow capturing parts of a request path until a "/"
363 or "." separator occurs, similar to the regular expression "([^/.]+)".
364 Results are accessible via "stash" in Mojolicious::Controller and
365 "param" in Mojolicious::Controller.
366
367 use Mojolicious::Lite;
368
369 # /foo/test
370 # /foo/test123
371 get '/foo/:bar' => sub {
372 my $c = shift;
373 my $bar = $c->stash('bar');
374 $c->render(text => "Our :bar placeholder matched $bar");
375 };
376
377 # /testsomething/foo
378 # /test123something/foo
379 get '/<:bar>something/foo' => sub {
380 my $c = shift;
381 my $bar = $c->param('bar');
382 $c->render(text => "Our :bar placeholder matched $bar");
383 };
384
385 app->start;
386
387 To separate them from the surrounding text, you can surround your
388 placeholders with "<" and ">", which also makes the colon prefix
389 optional.
390
391 Relaxed Placeholders
392 Relaxed placeholders allow matching of everything until a "/" occurs,
393 similar to the regular expression "([^/]+)".
394
395 use Mojolicious::Lite;
396
397 # /hello/test
398 # /hello/test.html
399 get '/hello/#you' => 'groovy';
400
401 app->start;
402 __DATA__
403
404 @@ groovy.html.ep
405 Your name is <%= $you %>.
406
407 Wildcard placeholders
408 Wildcard placeholders allow matching absolutely everything, including
409 "/" and ".", similar to the regular expression "(.+)".
410
411 use Mojolicious::Lite;
412
413 # /hello/test
414 # /hello/test123
415 # /hello/test.123/test/123
416 get '/hello/*you' => 'groovy';
417
418 app->start;
419 __DATA__
420
421 @@ groovy.html.ep
422 Your name is <%= $you %>.
423
424 HTTP methods
425 Routes can be restricted to specific request methods with different
426 keywords like "get" in Mojolicious::Lite and "any" in
427 Mojolicious::Lite.
428
429 use Mojolicious::Lite;
430
431 # GET /hello
432 get '/hello' => sub {
433 my $c = shift;
434 $c->render(text => 'Hello World!');
435 };
436
437 # PUT /hello
438 put '/hello' => sub {
439 my $c = shift;
440 my $size = length $c->req->body;
441 $c->render(text => "You uploaded $size bytes to /hello.");
442 };
443
444 # GET|POST|PATCH /bye
445 any ['GET', 'POST', 'PATCH'] => '/bye' => sub {
446 my $c = shift;
447 $c->render(text => 'Bye World!');
448 };
449
450 # * /whatever
451 any '/whatever' => sub {
452 my $c = shift;
453 my $method = $c->req->method;
454 $c->render(text => "You called /whatever with $method.");
455 };
456
457 app->start;
458
459 Optional placeholders
460 All placeholders require a value, but by assigning them default values
461 you can make capturing optional.
462
463 use Mojolicious::Lite;
464
465 # /hello
466 # /hello/Sara
467 get '/hello/:name' => {name => 'Sebastian', day => 'Monday'} => sub {
468 my $c = shift;
469 $c->render(template => 'groovy', format => 'txt');
470 };
471
472 app->start;
473 __DATA__
474
475 @@ groovy.txt.ep
476 My name is <%= $name %> and it is <%= $day %>.
477
478 Default values that don't belong to a placeholder simply get merged
479 into the stash all the time.
480
481 Restrictive placeholders
482 A very easy way to make placeholders more restrictive are alternatives,
483 you just make a list of possible values.
484
485 use Mojolicious::Lite;
486
487 # /test
488 # /123
489 any '/:foo' => [foo => ['test', '123']] => sub {
490 my $c = shift;
491 my $foo = $c->param('foo');
492 $c->render(text => "Our :foo placeholder matched $foo");
493 };
494
495 app->start;
496
497 All placeholders get compiled to a regular expression internally, this
498 process can also be customized. Just make sure not to use "^" and "$",
499 or capturing groups "(...)", non-capturing groups "(?:...)" are fine
500 though.
501
502 use Mojolicious::Lite;
503
504 # /1
505 # /123
506 any '/:bar' => [bar => qr/\d+/] => sub {
507 my $c = shift;
508 my $bar = $c->param('bar');
509 $c->render(text => "Our :bar placeholder matched $bar");
510 };
511
512 app->start;
513
514 You can take a closer look at all the generated regular expressions
515 with the command Mojolicious::Command::routes.
516
517 $ ./myapp.pl routes -v
518
519 Under
520 Authentication and code shared between multiple routes can be realized
521 easily with routes generated by "under" in Mojolicious::Lite. All
522 following routes are only evaluated if the callback returned a true
523 value.
524
525 use Mojolicious::Lite;
526
527 # Authenticate based on name parameter
528 under sub {
529 my $c = shift;
530
531 # Authenticated
532 my $name = $c->param('name') || '';
533 return 1 if $name eq 'Bender';
534
535 # Not authenticated
536 $c->render(template => 'denied');
537 return undef;
538 };
539
540 # Only reached when authenticated
541 get '/' => 'index';
542
543 app->start;
544 __DATA__
545
546 @@ denied.html.ep
547 You are not Bender, permission denied.
548
549 @@ index.html.ep
550 Hi Bender.
551
552 Prefixing multiple routes is another good use for it.
553
554 use Mojolicious::Lite;
555
556 # /foo
557 under '/foo';
558
559 # /foo/bar
560 get '/bar' => {text => 'foo bar'};
561
562 # /foo/baz
563 get '/baz' => {text => 'foo baz'};
564
565 # / (reset)
566 under '/' => {msg => 'whatever'};
567
568 # /bar
569 get '/bar' => {inline => '<%= $msg %> works'};
570
571 app->start;
572
573 You can also group related routes with "group" in Mojolicious::Lite,
574 which allows nesting of routes generated with "under" in
575 Mojolicious::Lite.
576
577 use Mojolicious::Lite;
578
579 # Global logic shared by all routes
580 under sub {
581 my $c = shift;
582 return 1 if $c->req->headers->header('X-Bender');
583 $c->render(text => "You're not Bender.");
584 return undef;
585 };
586
587 # Admin section
588 group {
589
590 # Local logic shared only by routes in this group
591 under '/admin' => sub {
592 my $c = shift;
593 return 1 if $c->req->headers->header('X-Awesome');
594 $c->render(text => "You're not awesome enough.");
595 return undef;
596 };
597
598 # GET /admin/dashboard
599 get '/dashboard' => {text => 'Nothing to see here yet.'};
600 };
601
602 # GET /welcome
603 get '/welcome' => {text => 'Hi Bender.'};
604
605 app->start;
606
607 Formats
608 Formats can be automatically detected from file extensions like
609 ".html", they are used to find the right template and generate the
610 correct "Content-Type" header.
611
612 use Mojolicious::Lite;
613
614 # /detection
615 # /detection.html
616 # /detection.txt
617 get '/detection' => sub {
618 my $c = shift;
619 $c->render(template => 'detected');
620 };
621
622 app->start;
623 __DATA__
624
625 @@ detected.html.ep
626 <!DOCTYPE html>
627 <html>
628 <head><title>Detected</title></head>
629 <body>HTML was detected.</body>
630 </html>
631
632 @@ detected.txt.ep
633 TXT was detected.
634
635 The default format is "html", and restrictive placeholders can be used
636 to limit possible values.
637
638 use Mojolicious::Lite;
639
640 # /hello.json
641 # /hello.txt
642 get '/hello' => [format => ['json', 'txt']] => sub {
643 my $c = shift;
644 return $c->render(json => {hello => 'world'})
645 if $c->stash('format') eq 'json';
646 $c->render(text => 'hello world');
647 };
648
649 app->start;
650
651 Or you can just disable format detection with a special type of
652 restrictive placeholder.
653
654 use Mojolicious::Lite;
655
656 # /hello
657 get '/hello' => [format => 0] => {text => 'No format detection.'};
658
659 # Disable detection and allow the following routes to re-enable it on demand
660 under [format => 0];
661
662 # /foo
663 get '/foo' => {text => 'No format detection again.'};
664
665 # /bar.txt
666 get '/bar' => [format => 'txt'] => {text => ' Just one format.'};
667
668 app->start;
669
670 Content negotiation
671 For resources with different representations and that require truly
672 RESTful content negotiation you can also use "respond_to" in
673 Mojolicious::Plugin::DefaultHelpers.
674
675 use Mojolicious::Lite;
676
677 # /hello (Accept: application/json)
678 # /hello (Accept: application/xml)
679 # /hello.json
680 # /hello.xml
681 # /hello?format=json
682 # /hello?format=xml
683 get '/hello' => sub {
684 my $c = shift;
685 $c->respond_to(
686 json => {json => {hello => 'world'}},
687 xml => {text => '<hello>world</hello>'},
688 any => {data => '', status => 204}
689 );
690 };
691
692 app->start;
693
694 MIME type mappings can be extended or changed easily with "types" in
695 Mojolicious.
696
697 app->types->type(rdf => 'application/rdf+xml');
698
699 Static files
700 Similar to templates, but with only a single file extension and
701 optional Base64 encoding, static files can be inlined in the "DATA"
702 section and are served automatically.
703
704 use Mojolicious::Lite;
705
706 app->start;
707 __DATA__
708
709 @@ something.js
710 alert('hello!');
711
712 @@ test.txt (base64)
713 dGVzdCAxMjMKbGFsYWxh
714
715 External static files are not limited to a single file extension and
716 will be served automatically from a "public" directory if it exists.
717
718 $ mkdir public
719 $ mv something.js public/something.js
720 $ mv mojolicious.tar.gz public/mojolicious.tar.gz
721
722 Both have a higher precedence than routes for "GET" and "HEAD"
723 requests. Content negotiation with "Range", "If-None-Match" and
724 "If-Modified-Since" headers is supported as well and can be tested very
725 easily with Mojolicious::Command::get.
726
727 $ ./myapp.pl get /something.js -v -H 'Range: bytes=2-4'
728
729 External templates
730 External templates will be searched by the renderer in a "templates"
731 directory if it exists.
732
733 $ mkdir -p templates/foo
734 $ echo 'Hello World!' > templates/foo/bar.html.ep
735
736 They have a higher precedence than templates in the "DATA" section.
737
738 use Mojolicious::Lite;
739
740 # Render template "templates/foo/bar.html.ep"
741 any '/external' => sub {
742 my $c = shift;
743 $c->render(template => 'foo/bar');
744 };
745
746 app->start;
747
748 Home
749 You can use "home" in Mojolicious to interact with the directory your
750 application considers its home. This is the directory it will search
751 for "public" and "templates" directories, but you can use it to store
752 all sorts of application specific data.
753
754 $ mkdir cache
755 $ echo 'Hello World!' > cache/hello.txt
756
757 There are many useful methods Mojo::Home inherits from Mojo::File, like
758 "child" in Mojo::File and "slurp" in Mojo::File, that will help you
759 keep your application portable across many different operating systems.
760
761 use Mojolicious::Lite;
762
763 # Load message into memory
764 my $hello = app->home->child('cache', 'hello.txt')->slurp;
765
766 # Display message
767 get '/' => sub {
768 my $c = shift;
769 $c->render(text => $hello);
770 };
771
772 You can also introspect your application from the command line with
773 Mojolicious::Command::eval.
774
775 $ ./myapp.pl eval -v 'app->home'
776
777 Conditions
778 Conditions such as "agent" and "host" from
779 Mojolicious::Plugin::HeaderCondition allow even more powerful route
780 constructs.
781
782 use Mojolicious::Lite;
783
784 # Firefox
785 get '/foo' => (agent => qr/Firefox/) => sub {
786 my $c = shift;
787 $c->render(text => 'Congratulations, you are using a cool browser.');
788 };
789
790 # Internet Explorer
791 get '/foo' => (agent => qr/Internet Explorer/) => sub {
792 my $c = shift;
793 $c->render(text => 'Dude, you really need to upgrade to Firefox.');
794 };
795
796 # http://mojolicious.org/bar
797 get '/bar' => (host => 'mojolicious.org') => sub {
798 my $c = shift;
799 $c->render(text => 'Hello Mojolicious.');
800 };
801
802 app->start;
803
804 Sessions
805 Cookie-based sessions just work out of the box, as soon as you start
806 using them through the helper "session" in
807 Mojolicious::Plugin::DefaultHelpers. Just be aware that all session
808 data gets serialized with Mojo::JSON and stored client-side, with a
809 cryptographic signature to prevent tampering.
810
811 use Mojolicious::Lite;
812
813 # Access session data in action and template
814 get '/counter' => sub {
815 my $c = shift;
816 $c->session->{counter}++;
817 };
818
819 app->start;
820 __DATA__
821
822 @@ counter.html.ep
823 Counter: <%= session 'counter' %>
824
825 Note that you should use custom "secrets" in Mojolicious to make signed
826 cookies really tamper resistant.
827
828 app->secrets(['My secret passphrase here']);
829
830 File uploads
831 All files uploaded via "multipart/form-data" request are automatically
832 available as Mojo::Upload objects from "param" in
833 Mojolicious::Controller. And you don't have to worry about memory
834 usage, because all files above 250KiB will be automatically streamed
835 into a temporary file. To build HTML forms more efficiently, you can
836 also use tag helpers like "form_for" in
837 Mojolicious::Plugin::TagHelpers.
838
839 use Mojolicious::Lite;
840
841 # Upload form in DATA section
842 get '/' => 'form';
843
844 # Multipart upload handler
845 post '/upload' => sub {
846 my $c = shift;
847
848 # Check file size
849 return $c->render(text => 'File is too big.', status => 200)
850 if $c->req->is_limit_exceeded;
851
852 # Process uploaded file
853 return $c->redirect_to('form') unless my $example = $c->param('example');
854 my $size = $example->size;
855 my $name = $example->filename;
856 $c->render(text => "Thanks for uploading $size byte file $name.");
857 };
858
859 app->start;
860 __DATA__
861
862 @@ form.html.ep
863 <!DOCTYPE html>
864 <html>
865 <head><title>Upload</title></head>
866 <body>
867 %= form_for upload => (enctype => 'multipart/form-data') => begin
868 %= file_field 'example'
869 %= submit_button 'Upload'
870 % end
871 </body>
872 </html>
873
874 To protect you from excessively large files there is also a limit of
875 16MiB by default, which you can tweak with the attribute
876 "max_request_size" in Mojolicious.
877
878 # Increase limit to 1GiB
879 app->max_request_size(1073741824);
880
881 User agent
882 With Mojo::UserAgent, which is available through the helper "ua" in
883 Mojolicious::Plugin::DefaultHelpers, there's a full featured HTTP and
884 WebSocket user agent built right in. Especially in combination with
885 Mojo::JSON and Mojo::DOM this can be a very powerful tool.
886
887 use Mojolicious::Lite;
888
889 # Blocking
890 get '/headers' => sub {
891 my $c = shift;
892 my $url = $c->param('url') || 'https://mojolicious.org';
893 my $dom = $c->ua->get($url)->result->dom;
894 $c->render(json => $dom->find('h1, h2, h3')->map('text')->to_array);
895 };
896
897 # Non-blocking
898 get '/title' => sub {
899 my $c = shift;
900 $c->ua->get('mojolicious.org' => sub {
901 my ($ua, $tx) = @_;
902 $c->render(data => $tx->result->dom->at('title')->text);
903 });
904 };
905
906 # Concurrent non-blocking
907 get '/titles' => sub {
908 my $c = shift;
909 my $mojo = $c->ua->get_p('https://mojolicious.org');
910 my $cpan = $c->ua->get_p('https://metacpan.org');
911 Mojo::Promise->all($mojo, $cpan)->then(sub {
912 my ($mojo, $cpan) = @_;
913 $c->render(json => {
914 mojo => $mojo->[0]->result->dom->at('title')->text,
915 cpan => $cpan->[0]->result->dom->at('title')->text
916 });
917 })->wait;
918 };
919
920 app->start;
921
922 For more information about the user agent see also "USER AGENT" in
923 Mojolicious::Guides::Cookbook.
924
925 WebSockets
926 WebSocket applications have never been this simple before. Just receive
927 messages by subscribing to events such as "json" in
928 Mojo::Transaction::WebSocket with "on" in Mojolicious::Controller and
929 return them with "send" in Mojolicious::Controller.
930
931 use Mojolicious::Lite;
932
933 websocket '/echo' => sub {
934 my $c = shift;
935 $c->on(json => sub {
936 my ($c, $hash) = @_;
937 $hash->{msg} = "echo: $hash->{msg}";
938 $c->send({json => $hash});
939 });
940 };
941
942 get '/' => 'index';
943
944 app->start;
945 __DATA__
946
947 @@ index.html.ep
948 <!DOCTYPE html>
949 <html>
950 <head>
951 <title>Echo</title>
952 <script>
953 var ws = new WebSocket('<%= url_for('echo')->to_abs %>');
954 ws.onmessage = function (event) {
955 document.body.innerHTML += JSON.parse(event.data).msg;
956 };
957 ws.onopen = function (event) {
958 ws.send(JSON.stringify({msg: 'I ♥ Mojolicious!'}));
959 };
960 </script>
961 </head>
962 </html>
963
964 For more information about real-time web features see also "REAL-TIME
965 WEB" in Mojolicious::Guides::Cookbook.
966
967 Mode
968 You can use the Mojo::Log object from "log" in Mojolicious to portably
969 collect debug messages and automatically disable them later in a
970 production setup by changing the Mojolicious operating mode, which can
971 also be retrieved from the attribute "mode" in Mojolicious.
972
973 use Mojolicious::Lite;
974
975 # Prepare mode specific message during startup
976 my $msg = app->mode eq 'development' ? 'Development!' : 'Something else!';
977
978 get '/' => sub {
979 my $c = shift;
980 $c->app->log->debug('Rendering mode specific message');
981 $c->render(text => $msg);
982 };
983
984 app->log->debug('Starting application');
985 app->start;
986
987 The default operating mode will usually be "development" and can be
988 changed with command line options or the "MOJO_MODE" and "PLACK_ENV"
989 environment variables. A mode other than "development" will raise the
990 log level from "debug" to "info".
991
992 $ ./myapp.pl daemon -m production
993
994 All messages will be written to "STDERR" or a "log/$mode.log" file if a
995 "log" directory exists.
996
997 $ mkdir log
998
999 Mode changes also affect a few other aspects of the framework, such as
1000 the built-in "exception" and "not_found" pages. Once you switch modes
1001 from "development" to "production", no sensitive information will be
1002 revealed on those pages anymore.
1003
1004 Testing
1005 Testing your application is as easy as creating a "t" directory and
1006 filling it with normal Perl tests like "t/basic.t", which can be a lot
1007 of fun thanks to Test::Mojo.
1008
1009 use Test::More;
1010 use Mojo::File qw(curfile);
1011 use Test::Mojo;
1012
1013 # Portably point to "../myapp.pl"
1014 my $script = curfile->dirname->sibling('myapp.pl');
1015
1016 my $t = Test::Mojo->new($script);
1017 $t->get_ok('/')->status_is(200)->content_like(qr/Funky/);
1018
1019 done_testing();
1020
1021 Just run your tests with prove.
1022
1023 $ prove -l -v
1024 $ prove -l -v t/basic.t
1025
1027 You can continue with Mojolicious::Guides now or take a look at the
1028 Mojolicious wiki <http://github.com/mojolicious/mojo/wiki>, which
1029 contains a lot more documentation and examples by many different
1030 authors.
1031
1033 If you have any questions the documentation might not yet answer, don't
1034 hesitate to ask on the mailing list
1035 <http://groups.google.com/group/mojolicious> or the official IRC
1036 channel "#mojo" on "irc.freenode.net" (chat now!
1037 <https://webchat.freenode.net/#mojo>).
1038
1039
1040
1041perl v5.32.0 2020-07-28 Mojolicious::Guides::Tutorial(3)