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://mojojs.org', 'mojo.js')
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. Use a restrictive placeholder to declare
590 the possible values.
591
592 use Mojolicious::Lite -signatures;
593
594 # /detection.html
595 # /detection.txt
596 get '/detection' => [format => ['html', 'txt']] => 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 And just like with placeholders you can use a default value to make the
614 format optional.
615
616 use Mojolicious::Lite -signatures;
617
618 # /hello
619 # /hello.json
620 # /hello.txt
621 get '/hello' => [format => ['json', 'txt']] => {format => 'txt'} => sub ($c) {
622 return $c->render(json => {hello => 'world'}) if $c->stash('format') eq 'json';
623 $c->render(text => 'hello world');
624 };
625
626 app->start;
627
628 The default format is "html" and the renderer will fall back to when
629 necessary.
630
631 Content negotiation
632 For resources with different representations and that require truly
633 RESTful content negotiation you can also use "respond_to" in
634 Mojolicious::Plugin::DefaultHelpers.
635
636 use Mojolicious::Lite -signatures;
637
638 # /hello (Accept: application/json)
639 # /hello (Accept: application/xml)
640 # /hello.json
641 # /hello.xml
642 # /hello?_format=json
643 # /hello?_format=xml
644 get '/hello' => [format => ['json', 'xml']] => {format => undef} => sub ($c) {
645 $c->respond_to(
646 json => {json => {hello => 'world'}},
647 xml => {text => '<hello>world</hello>'},
648 any => {data => '', status => 204}
649 );
650 };
651
652 app->start;
653
654 MIME type mappings can be extended or changed easily with "types" in
655 Mojolicious.
656
657 app->types->type(rdf => 'application/rdf+xml');
658
659 Static files
660 Similar to templates, but with only a single file extension and
661 optional Base64 encoding, static files can be inlined in the "DATA"
662 section and are served automatically.
663
664 use Mojolicious::Lite;
665
666 app->start;
667 __DATA__
668
669 @@ something.js
670 alert('hello!');
671
672 @@ test.txt (base64)
673 dGVzdCAxMjMKbGFsYWxh
674
675 External static files are not limited to a single file extension and
676 will be served automatically from a "public" directory if it exists.
677
678 $ mkdir public
679 $ mv something.js public/something.js
680 $ mv mojolicious.tar.gz public/mojolicious.tar.gz
681
682 Both have a higher precedence than routes for "GET" and "HEAD"
683 requests. Content negotiation with "Range", "If-None-Match" and
684 "If-Modified-Since" headers is supported as well and can be tested very
685 easily with Mojolicious::Command::get.
686
687 $ ./myapp.pl get /something.js -v -H 'Range: bytes=2-4'
688
689 External templates
690 External templates will be searched by the renderer in a "templates"
691 directory if it exists.
692
693 $ mkdir -p templates/foo
694 $ echo 'Hello World!' > templates/foo/bar.html.ep
695
696 They have a higher precedence than templates in the "DATA" section.
697
698 use Mojolicious::Lite -signatures;
699
700 # Render template "templates/foo/bar.html.ep"
701 any '/external' => sub ($c) {
702 $c->render(template => 'foo/bar');
703 };
704
705 app->start;
706
707 Home
708 You can use "home" in Mojolicious to interact with the directory your
709 application considers its home. This is the directory it will search
710 for "public" and "templates" directories, but you can use it to store
711 all sorts of application specific data.
712
713 $ mkdir cache
714 $ echo 'Hello World!' > cache/hello.txt
715
716 There are many useful methods Mojo::Home inherits from Mojo::File, like
717 "child" in Mojo::File and "slurp" in Mojo::File, that will help you
718 keep your application portable across many different operating systems.
719
720 use Mojolicious::Lite -signatures;
721
722 # Load message into memory
723 my $hello = app->home->child('cache', 'hello.txt')->slurp;
724
725 # Display message
726 get '/' => sub ($c) {
727 $c->render(text => $hello);
728 };
729
730 You can also introspect your application from the command line with
731 Mojolicious::Command::eval.
732
733 $ ./myapp.pl eval -v 'app->home'
734
735 Conditions
736 Conditions such as "agent" and "host" from
737 Mojolicious::Plugin::HeaderCondition allow even more powerful route
738 constructs.
739
740 use Mojolicious::Lite -signatures;
741
742 # Firefox
743 get '/foo' => (agent => qr/Firefox/) => sub ($c) {
744 $c->render(text => 'Congratulations, you are using a cool browser.');
745 };
746
747 # Internet Explorer
748 get '/foo' => (agent => qr/Internet Explorer/) => sub ($c) {
749 $c->render(text => 'Dude, you really need to upgrade to Firefox.');
750 };
751
752 # http://mojolicious.org/bar
753 get '/bar' => (host => 'mojolicious.org') => sub ($c) {
754 $c->render(text => 'Hello Mojolicious.');
755 };
756
757 app->start;
758
759 Sessions
760 Cookie-based sessions just work out of the box, as soon as you start
761 using them through the helper "session" in
762 Mojolicious::Plugin::DefaultHelpers. Just be aware that all session
763 data gets serialized with Mojo::JSON and stored client-side, with a
764 cryptographic signature to prevent tampering.
765
766 use Mojolicious::Lite -signatures;
767
768 # Access session data in action and template
769 get '/counter' => sub ($c) {
770 $c->session->{counter}++;
771 };
772
773 app->start;
774 __DATA__
775
776 @@ counter.html.ep
777 Counter: <%= session 'counter' %>
778
779 Note that you should use custom "secrets" in Mojolicious to make signed
780 cookies really tamper resistant.
781
782 app->secrets(['My secret passphrase here']);
783
784 File uploads
785 All files uploaded via "multipart/form-data" request are automatically
786 available as Mojo::Upload objects from "param" in
787 Mojolicious::Controller. And you don't have to worry about memory
788 usage, because all files above 250KiB will be automatically streamed
789 into a temporary file. To build HTML forms more efficiently, you can
790 also use tag helpers like "form_for" in
791 Mojolicious::Plugin::TagHelpers.
792
793 use Mojolicious::Lite -signatures;
794
795 # Upload form in DATA section
796 get '/' => 'form';
797
798 # Multipart upload handler
799 post '/upload' => sub ($c) {
800
801 # Check file size
802 return $c->render(text => 'File is too big.', status => 200) if $c->req->is_limit_exceeded;
803
804 # Process uploaded file
805 return $c->redirect_to('form') unless my $example = $c->param('example');
806 my $size = $example->size;
807 my $name = $example->filename;
808 $c->render(text => "Thanks for uploading $size byte file $name.");
809 };
810
811 app->start;
812 __DATA__
813
814 @@ form.html.ep
815 <!DOCTYPE html>
816 <html>
817 <head><title>Upload</title></head>
818 <body>
819 %= form_for upload => (enctype => 'multipart/form-data') => begin
820 %= file_field 'example'
821 %= submit_button 'Upload'
822 % end
823 </body>
824 </html>
825
826 To protect you from excessively large files there is also a limit of
827 16MiB by default, which you can tweak with the attribute
828 "max_request_size" in Mojolicious.
829
830 # Increase limit to 1GiB
831 app->max_request_size(1073741824);
832
833 User agent
834 With Mojo::UserAgent, which is available through the helper "ua" in
835 Mojolicious::Plugin::DefaultHelpers, there's a full featured HTTP and
836 WebSocket user agent built right in. Especially in combination with
837 Mojo::JSON and Mojo::DOM this can be a very powerful tool.
838
839 use Mojolicious::Lite -signatures;
840
841 # Blocking
842 get '/headers' => sub ($c) {
843 my $url = $c->param('url') || 'https://mojolicious.org';
844 my $dom = $c->ua->get($url)->result->dom;
845 $c->render(json => $dom->find('h1, h2, h3')->map('text')->to_array);
846 };
847
848 # Non-blocking
849 get '/title' => sub ($c) {
850 $c->ua->get('mojolicious.org' => sub ($ua, $tx) {
851 $c->render(data => $tx->result->dom->at('title')->text);
852 });
853 };
854
855 # Concurrent non-blocking
856 get '/titles' => sub ($c) {
857 my $mojo = $c->ua->get_p('https://mojolicious.org');
858 my $cpan = $c->ua->get_p('https://metacpan.org');
859 Mojo::Promise->all($mojo, $cpan)->then(sub ($mojo, $cpan) {
860 $c->render(json => {
861 mojo => $mojo->[0]->result->dom->at('title')->text,
862 cpan => $cpan->[0]->result->dom->at('title')->text
863 });
864 })->wait;
865 };
866
867 app->start;
868
869 For more information about the user agent see also "USER AGENT" in
870 Mojolicious::Guides::Cookbook.
871
872 WebSockets
873 WebSocket applications have never been this simple before. Just receive
874 messages by subscribing to events such as "json" in
875 Mojo::Transaction::WebSocket with "on" in Mojolicious::Controller and
876 return them with "send" in Mojolicious::Controller.
877
878 use Mojolicious::Lite -signatures;
879
880 websocket '/echo' => sub ($c) {
881 $c->on(json => sub ($c, $hash) {
882 $hash->{msg} = "echo: $hash->{msg}";
883 $c->send({json => $hash});
884 });
885 };
886
887 get '/' => 'index';
888
889 app->start;
890 __DATA__
891
892 @@ index.html.ep
893 <!DOCTYPE html>
894 <html>
895 <head>
896 <title>Echo</title>
897 <script>
898 const ws = new WebSocket('<%= url_for('echo')->to_abs %>');
899 ws.onmessage = function (event) {
900 document.body.innerHTML += JSON.parse(event.data).msg;
901 };
902 ws.onopen = function (event) {
903 ws.send(JSON.stringify({msg: 'I ♥ Mojolicious!'}));
904 };
905 </script>
906 </head>
907 </html>
908
909 For more information about real-time web features see also "REAL-TIME
910 WEB" in Mojolicious::Guides::Cookbook.
911
912 Mode
913 You can use the Mojo::Log object from "log" in Mojolicious to portably
914 collect debug messages and automatically disable them later in a
915 production setup by changing the Mojolicious operating mode, which can
916 also be retrieved from the attribute "mode" in Mojolicious.
917
918 use Mojolicious::Lite -signatures;
919
920 # Prepare mode specific message during startup
921 my $msg = app->mode eq 'development' ? 'Development!' : 'Something else!';
922
923 get '/' => sub ($c) {
924 $c->app->log->debug('Rendering mode specific message');
925 $c->render(text => $msg);
926 };
927
928 app->log->debug('Starting application');
929 app->start;
930
931 The default operating mode will usually be "development" and can be
932 changed with command line options or the "MOJO_MODE" and "PLACK_ENV"
933 environment variables. A mode other than "development" will raise the
934 log level from "trace" to "info". All messages will be written to
935 "STDERR" by default.
936
937 $ ./myapp.pl daemon -m production
938
939 Mode changes also affect a few other aspects of the framework, such as
940 the built-in "exception" and "not_found" pages. Once you switch modes
941 from "development" to "production", no sensitive information will be
942 revealed on those pages anymore.
943
944 Testing
945 Testing your application is as easy as creating a "t" directory and
946 filling it with normal Perl tests like "t/basic.t", which can be a lot
947 of fun thanks to Test::Mojo.
948
949 use Test::More;
950 use Mojo::File qw(curfile);
951 use Test::Mojo;
952
953 # Portably point to "../myapp.pl"
954 my $script = curfile->dirname->sibling('myapp.pl');
955
956 my $t = Test::Mojo->new($script);
957 $t->get_ok('/')->status_is(200)->content_like(qr/Funky/);
958
959 done_testing();
960
961 Just run your tests with prove.
962
963 $ prove -l -v
964 $ prove -l -v t/basic.t
965
967 You can continue with Mojolicious::Guides now or take a look at the
968 Mojolicious wiki <https://github.com/mojolicious/mojo/wiki>, which
969 contains a lot more documentation and examples by many different
970 authors.
971
973 If you have any questions the documentation might not yet answer, don't
974 hesitate to ask in the Forum <https://forum.mojolicious.org>, on Matrix
975 <https://matrix.to/#/#mojo:matrix.org>, or IRC
976 <https://web.libera.chat/#mojo>.
977
978
979
980perl v5.36.0 2023-01-20 Mojolicious::Guides::Tutorial(3)