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