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

MORE

1001       You can continue with Mojolicious::Guides now or take a look at the
1002       Mojolicious wiki <http://github.com/mojolicious/mojo/wiki>, which
1003       contains a lot more documentation and examples by many different
1004       authors.
1005

SUPPORT

1007       If you have any questions the documentation might not yet answer, don't
1008       hesitate to ask on the mailing list
1009       <http://groups.google.com/group/mojolicious> or the official IRC
1010       channel "#mojo" on "irc.freenode.net" (chat now!
1011       <https://kiwiirc.com/nextclient/#irc://irc.freenode.net/mojo?nick=guest-?>).
1012
1013
1014
1015perl v5.28.1                      2018-11-01  Mojolicious::Guides::Tutorial(3)
Impressum