1Mojolicious::Guides::TuUtsoerriaClo(n3t)ributed Perl DocMuomjeonltiactiioouns::Guides::Tutorial(3)
2
3
4

NAME

6       Mojolicious::Guides::Tutorial - Get started with Mojolicious
7

TUTORIAL

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

MORE

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

SUPPORT

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)
Impressum