1Mojolicious::Guides::RoUusteirngC(o3n)tributed Perl DocuMmoejnotlaitciioonus::Guides::Routing(3)
2
3
4
6 Mojolicious::Guides::Routing - Routing requests
7
9 This document contains a simple and fun introduction to the Mojolicious
10 router and its underlying concepts.
11
13 Essentials every Mojolicious developer should know.
14
15 Dispatcher
16 The foundation of every web framework is a tiny black box connecting
17 incoming requests with code generating the appropriate response.
18
19 GET /user/show/1 -> $c->render(text => 'Daniel');
20
21 This black box is usually called a dispatcher. There are many
22 implementations using different strategies to establish these
23 connections, but pretty much all are based around mapping the path part
24 of the request URL to some kind of response generator.
25
26 /user/show/2 -> $c->render(text => 'Isabell');
27 /user/show/3 -> $c->render(text => 'Sara');
28 /user/show/4 -> $c->render(text => 'Stefan');
29 /user/show/5 -> $c->render(text => 'Fynn');
30
31 While it is very well possible to make all these connections static, it
32 is also rather inefficient. That's why regular expressions are commonly
33 used to make the dispatch process more dynamic.
34
35 qr!/user/show/(\d+)! -> $c->render(text => $users{$1});
36
37 Modern dispatchers have pretty much everything HTTP has to offer at
38 their disposal and can use many more variables than just the request
39 path, such as request method and headers like "Host", "User-Agent" and
40 "Accept".
41
42 GET /user/show/23 HTTP/1.1
43 Host: mojolicious.org
44 User-Agent: Mojolicious (Perl)
45 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
46
47 Routes
48 While regular expressions are quite powerful they also tend to be
49 unpleasant to look at and are generally overkill for ordinary path
50 matching.
51
52 qr!/user/admin/(\d+)! -> $c->render(text => $users{$1});
53
54 This is where routes come into play, they have been designed from the
55 ground up to represent paths with placeholders.
56
57 /user/admin/:id -> $c->render(text => $users{$id});
58
59 The only difference between a static path and the route above is the
60 ":id" placeholder. One or more placeholders can be anywhere in the
61 route.
62
63 /user/:role/:id
64
65 A fundamental concept of the Mojolicious router is that extracted
66 placeholder values are turned into a hash.
67
68 /user/admin/23 -> /user/:role/:id -> {role => 'admin', id => 23}
69
70 This hash is basically the center of every Mojolicious application, you
71 will learn more about this later on. Internally, routes get compiled
72 to regular expressions, so you can get the best of both worlds with a
73 little bit of experience.
74
75 /user/admin/:id -> qr/(?-xism:^\/user\/admin\/([^\/.]+))/
76
77 A trailing slash in the path is always optional.
78
79 /user/admin/23/ -> /user/:role/:id -> {role => 'admin', id => 23}
80
81 Reversibility
82 One more huge advantage routes have over regular expressions is that
83 they are easily reversible, extracted placeholders can be turned back
84 into a path at any time.
85
86 /sebastian -> /:name -> {name => 'sebastian'}
87 {name => 'sebastian'} -> /:name -> /sebastian
88
89 Every placeholder has a name, even if it's just an empty string.
90
91 Standard placeholders
92 Standard placeholders are the simplest form of placeholders, they use a
93 colon prefix and match all characters except "/" and ".", similar to
94 the regular expression "([^/.]+)".
95
96 /hello -> /:name/hello -> undef
97 /sebastian/23/hello -> /:name/hello -> undef
98 /sebastian.23/hello -> /:name/hello -> undef
99 /sebastian/hello -> /:name/hello -> {name => 'sebastian'}
100 /sebastian23/hello -> /:name/hello -> {name => 'sebastian23'}
101 /sebastian 23/hello -> /:name/hello -> {name => 'sebastian 23'}
102
103 All placeholders can be surrounded by "<" and ">" to separate them from
104 the surrounding text.
105
106 /hello -> /<:name>hello -> undef
107 /sebastian/23hello -> /<:name>hello -> undef
108 /sebastian.23hello -> /<:name>hello -> undef
109 /sebastianhello -> /<:name>hello -> {name => 'sebastian'}
110 /sebastian23hello -> /<:name>hello -> {name => 'sebastian23'}
111 /sebastian 23hello -> /<:name>hello -> {name => 'sebastian 23'}
112
113 The colon prefix is optional for standard placeholders that are
114 surrounded by "<" and ">".
115
116 /i♥mojolicious -> /<one>♥<two> -> {one => 'i', two => 'mojolicious'}
117
118 Relaxed placeholders
119 Relaxed placeholders are just like standard placeholders, but use a
120 hash prefix and match all characters except "/", similar to the regular
121 expression "([^/]+)".
122
123 /hello -> /#name/hello -> undef
124 /sebastian/23/hello -> /#name/hello -> undef
125 /sebastian.23/hello -> /#name/hello -> {name => 'sebastian.23'}
126 /sebastian/hello -> /#name/hello -> {name => 'sebastian'}
127 /sebastian23/hello -> /#name/hello -> {name => 'sebastian23'}
128 /sebastian 23/hello -> /#name/hello -> {name => 'sebastian 23'}
129
130 They can be especially useful for manually matching file names with
131 extensions, rather than using format detection.
132
133 /music/song.mp3 -> /music/#filename -> {filename => 'song.mp3'}
134
135 Wildcard placeholders
136 Wildcard placeholders are just like the two types of placeholders
137 above, but use an asterisk prefix and match absolutely everything,
138 including "/" and ".", similar to the regular expression "(.+)".
139
140 /hello -> /*name/hello -> undef
141 /sebastian/23/hello -> /*name/hello -> {name => 'sebastian/23'}
142 /sebastian.23/hello -> /*name/hello -> {name => 'sebastian.23'}
143 /sebastian/hello -> /*name/hello -> {name => 'sebastian'}
144 /sebastian23/hello -> /*name/hello -> {name => 'sebastian23'}
145 /sebastian 23/hello -> /*name/hello -> {name => 'sebastian 23'}
146
147 They can be useful for manually matching entire file paths.
148
149 /music/rock/song.mp3 -> /music/*filepath -> {filepath => 'rock/song.mp3'}
150
152 Most commonly used features every Mojolicious developer should know
153 about.
154
155 Minimal route
156 The attribute "routes" in Mojolicious contains a router you can use to
157 generate route structures.
158
159 # Application
160 package MyApp;
161 use Mojo::Base 'Mojolicious', -signatures;
162
163 sub startup ($self) {
164 # Router
165 my $r = $self->routes;
166
167 # Route
168 $r->get('/welcome')->to(controller => 'foo', action => 'welcome');
169 }
170
171 1;
172
173 The minimal route above will load and instantiate the class
174 "MyApp::Controller::Foo" and call its "welcome" method. Routes are
175 usually configured in the "startup" method of the application class,
176 but the router can be accessed from everywhere (even at runtime).
177
178 # Controller
179 package MyApp::Controller::Foo;
180 use Mojo::Base 'Mojolicious::Controller', -signatures;
181
182 # Action
183 sub welcome ($self) {
184 # Render response
185 $self->render(text => 'Hello there.');
186 }
187
188 1;
189
190 All routes match in the same order in which they were defined, and
191 matching stops as soon as a suitable route has been found. So you can
192 improve the routing performance by declaring your most frequently
193 accessed routes first. A routing cache will also be used automatically
194 to handle sudden traffic spikes more gracefully.
195
196 Routing destination
197 After you start a new route with methods like "get" in
198 Mojolicious::Routes::Route, you can also give it a destination in the
199 form of a hash using the chained method "to" in
200 Mojolicious::Routes::Route.
201
202 # /welcome -> {controller => 'foo', action => 'welcome'}
203 $r->get('/welcome')->to(controller => 'foo', action => 'welcome');
204
205 Now if the route matches an incoming request it will use the content of
206 this hash to try and find appropriate code to generate a response.
207
208 HTTP methods
209 There are already shortcuts for the most common HTTP request methods
210 like "post" in Mojolicious::Routes::Route, and for more control "any"
211 in Mojolicious::Routes::Route accepts an optional array reference with
212 arbitrary request methods as first argument.
213
214 # PUT /hello -> undef
215 # GET /hello -> {controller => 'foo', action => 'hello'}
216 $r->get('/hello')->to(controller => 'foo', action => 'hello');
217
218 # PUT /hello -> {controller => 'foo', action => 'hello'}
219 $r->put('/hello')->to(controller => 'foo', action => 'hello');
220
221 # POST /hello -> {controller => 'foo', action => 'hello'}
222 $r->post('/hello')->to(controller => 'foo', action => 'hello');
223
224 # GET|POST /bye -> {controller => 'foo', action => 'bye'}
225 $r->any(['GET', 'POST'] => '/bye')->to(controller => 'foo', action => 'bye');
226
227 # * /whatever -> {controller => 'foo', action => 'whatever'}
228 $r->any('/whatever')->to(controller => 'foo', action => 'whatever');
229
230 There is one small exception, "HEAD" requests are considered equal to
231 "GET", but content will not be sent with the response even if it is
232 present.
233
234 # GET /test -> {controller => 'bar', action => 'test'}
235 # HEAD /test -> {controller => 'bar', action => 'test'}
236 $r->get('/test')->to(controller => 'bar', action => 'test');
237
238 You can also use the "_method" query parameter to override the request
239 method. This can be very useful when submitting forms with browsers
240 that only support "GET" and "POST".
241
242 # PUT /stuff -> {controller => 'baz', action => 'stuff'}
243 # POST /stuff?_method=PUT -> {controller => 'baz', action => 'stuff'}
244 $r->put('/stuff')->to(controller => 'baz', action => 'stuff');
245
246 IRIs
247 IRIs are handled transparently, that means paths are guaranteed to be
248 unescaped and decoded from bytes to characters.
249
250 # GET /☃ (Unicode snowman) -> {controller => 'foo', action => 'snowman'}
251 $r->get('/☃')->to(controller => 'foo', action => 'snowman');
252
253 Stash
254 The generated hash of a matching route is actually the center of the
255 whole Mojolicious request cycle. We call it the stash, and it persists
256 until a response has been generated.
257
258 # /bye -> {controller => 'foo', action => 'bye', mymessage => 'Bye'}
259 $r->get('/bye')->to(controller => 'foo', action => 'bye', mymessage => 'Bye');
260
261 There are a few stash values with special meaning, such as "controller"
262 and "action", but you can generally fill it with whatever data you need
263 to generate a response. Once dispatched the whole stash content can be
264 changed at any time.
265
266 sub bye ($self) {
267
268 # Get message from stash
269 my $msg = $self->stash('mymessage');
270
271 # Change message in stash
272 $self->stash(mymessage => 'Welcome');
273 }
274
275 For a full list of reserved stash values see "stash" in
276 Mojolicious::Controller.
277
278 Nested routes
279 It is also possible to build tree structures from routes to remove
280 repetitive code. A route with children can't match on its own though,
281 only the actual endpoints of these nested routes can.
282
283 # /foo -> undef
284 # /foo/bar -> {controller => 'foo', action => 'bar'}
285 my $foo = $r->any('/foo')->to(controller => 'foo');
286 $foo->get('/bar')->to(action => 'bar');
287
288 The stash is simply inherited from route to route and newer values
289 override old ones.
290
291 # /cats -> {controller => 'cats', action => 'index'}
292 # /cats/nyan -> {controller => 'cats', action => 'nyan'}
293 # /cats/lol -> {controller => 'cats', action => 'default'}
294 my $cats = $r->any('/cats')->to(controller => 'cats', action => 'default');
295 $cats->get('/')->to(action => 'index');
296 $cats->get('/nyan')->to(action => 'nyan');
297 $cats->get('/lol');
298
299 With a few common prefixes you can also greatly improve the routing
300 performance of applications with many routes, because children are only
301 tried if the prefix matched first.
302
303 Special stash values
304 When the dispatcher sees "controller" and "action" values in the stash
305 it will always try to turn them into a class and method to dispatch to.
306 The "controller" value gets converted from "snake_case" to "CamelCase"
307 using "camelize" in Mojo::Util and appended to one or more namespaces,
308 defaulting to a controller namespace based on the application class
309 ("MyApp::Controller"), as well as the bare application class ("MyApp"),
310 and these namespaces are searched in that order. The action value is
311 not changed at all, so both values are case-sensitive.
312
313 # Application
314 package MyApp;
315 use Mojo::Base 'Mojolicious', -signatures;
316
317 sub startup ($self) {
318 # /bye -> MyApp::Controller::Foo->bye
319 $self->routes->get('/bye')->to(controller => 'foo', action => 'bye');
320 }
321
322 1;
323
324 # Controller
325 package MyApp::Controller::Foo;
326 use Mojo::Base 'Mojolicious::Controller', -signatures;
327
328 # Action
329 sub bye ($self) {
330 # Render response
331 $self->render(text => 'Good bye.');
332 }
333
334 1;
335
336 Controller classes are perfect for organizing code in larger projects.
337 There are more dispatch strategies, but because controllers are the
338 most commonly used ones they also got a special shortcut in the form of
339 "controller#action".
340
341 # /bye -> {controller => 'foo', action => 'bye', mymessage => 'Bye'}
342 $r->get('/bye')->to('foo#bye', mymessage => 'Bye');
343
344 During camelization "-" characters get replaced with "::", this allows
345 multi-level "controller" hierarchies.
346
347 # / -> MyApp::Controller::Foo::Bar->hi
348 $r->get('/')->to('foo-bar#hi');
349
350 You can also just specify the "controller" in CamelCase form instead of
351 snake_case.
352
353 # / -> MyApp::Controller::Foo::Bar->hi
354 $r->get('/')->to('Foo::Bar#hi');
355
356 For security reasons the dispatcher will always check if the
357 "controller" is actually a subclass of Mojolicious::Controller or Mojo
358 before dispatching to it.
359
360 Namespaces
361 You can use the "namespace" stash value to change the namespace of a
362 whole route with all its children.
363
364 # /bye -> MyApp::MyController::Foo::Bar->bye
365 $r->get('/bye')->to(namespace => 'MyApp::MyController::Foo::Bar', action => 'bye');
366
367 The "controller" is always converted from "snake_case" to "CamelCase"
368 with "camelize" in Mojo::Util, and then appended to this "namespace".
369
370 # /bye -> MyApp::MyController::Foo::Bar->bye
371 $r->get('/bye')->to('foo-bar#bye', namespace => 'MyApp::MyController');
372
373 # /hey -> MyApp::MyController::Foo::Bar->hey
374 $r->get('/hey')->to('Foo::Bar#hey', namespace => 'MyApp::MyController');
375
376 You can also change the default namespaces for all routes in the
377 application with the router attribute "namespaces" in
378 Mojolicious::Routes, which usually defaults to a namespace based on the
379 application class ("MyApp::Controller"), as well as the bare
380 application class ("MyApp").
381
382 $r->namespaces(['MyApp::MyController']);
383
384 Route to callback
385 The "cb" stash value, which won't be inherited by nested routes, can be
386 used to bypass controllers and execute a callback instead.
387
388 $r->get('/bye')->to(cb => sub ($c) {
389 $c->render(text => 'Good bye.');
390 });
391
392 But just like in Mojolicious::Lite you can also pass the callback
393 directly, which usually looks much better.
394
395 $r->get('/bye' => sub ($c) {
396 $c->render(text => 'Good bye.');
397 });
398
399 Named routes
400 Naming your routes will allow backreferencing in many methods and
401 helpers throughout the whole framework, most of which internally rely
402 on "url_for" in Mojolicious::Controller for this.
403
404 # /foo/marcus -> {controller => 'foo', action => 'bar', user => 'marcus'}
405 $r->get('/foo/:user')->to('foo#bar')->name('baz');
406
407 # Generate URL "/foo/marcus" for route "baz" (in previous request context)
408 my $url = $c->url_for('baz');
409
410 # Generate URL "/foo/jan" for route "baz"
411 my $url = $c->url_for('baz', user => 'jan');
412
413 # Generate URL "http://127.0.0.1:3000/foo/jan" for route "baz"
414 my $url = $c->url_for('baz', user => 'jan')->to_abs;
415
416 You can assign a name with "name" in Mojolicious::Routes::Route, or let
417 the router generate one automatically, which would be equal to the
418 route itself without non-word characters, custom names have a higher
419 precedence though.
420
421 # /foo/bar ("foobar")
422 $r->get('/foo/bar')->to('test#stuff');
423
424 # Generate URL "/foo/bar"
425 my $url = $c->url_for('foobar');
426
427 To refer to the current route you can use the reserved name "current"
428 or no name at all.
429
430 # Generate URL for current route
431 my $url = $c->url_for('current');
432 my $url = $c->url_for;
433
434 To check or get the name of the current route you can use the helper
435 "current_route" in Mojolicious::Plugin::DefaultHelpers.
436
437 # Name for current route
438 my $name = $c->current_route;
439
440 # Check route name in code shared by multiple routes
441 $c->stash(button => 'green') if $c->current_route('login');
442
443 Optional placeholders
444 Extracted placeholder values will simply redefine older stash values if
445 they already exist.
446
447 # /bye -> {controller => 'foo', action => 'bar', mymessage => 'bye'}
448 # /hey -> {controller => 'foo', action => 'bar', mymessage => 'hey'}
449 $r->get('/:mymessage')->to('foo#bar', mymessage => 'hi');
450
451 One more interesting effect, a placeholder automatically becomes
452 optional if there is already a stash value of the same name present,
453 this works similar to the regular expression "([^/.]+)?".
454
455 # / -> {controller => 'foo', action => 'bar', mymessage => 'hi'}
456 $r->get('/:mymessage')->to('foo#bar', mymessage => 'hi');
457
458 # /test/123 -> {controller => 'foo', action => 'bar', mymessage => 'hi'}
459 # /test/bye/123 -> {controller => 'foo', action => 'bar', mymessage => 'bye'}
460 $r->get('/test/:mymessage/123')->to('foo#bar', mymessage => 'hi');
461
462 And if two optional placeholders are only separated by a slash, that
463 slash can become optional as well.
464
465 # / -> {controller => 'foo', action => 'bar'}
466 # /users -> {controller => 'users', action => 'bar'}
467 # /users/list -> {controller => 'users', action => 'list'}
468 $r->get('/:controller/:action')->to('foo#bar');
469
470 Special stash values like "controller" and "action" can also be
471 placeholders, which is very convenient especially during development,
472 but should only be used very carefully, because every controller method
473 becomes a potential route. All uppercase methods as well as those
474 starting with an underscore are automatically hidden from the router
475 and you can use "hide" in Mojolicious::Routes to add additional ones.
476
477 # Hide "create" method in all controllers
478 $r->hide('create');
479
480 This has already been done for all attributes and methods from
481 Mojolicious::Controller.
482
483 Restrictive placeholders
484 A very easy way to make placeholders more restrictive are alternatives,
485 you just make a list of possible values, which then work similar to the
486 regular expression "(bender|leela)".
487
488 # /fry -> undef
489 # /bender -> {controller => 'foo', action => 'bar', name => 'bender'}
490 # /leela -> {controller => 'foo', action => 'bar', name => 'leela'}
491 $r->get('/:name' => [name => ['bender', 'leela']])->to('foo#bar');
492
493 You can also adjust the regular expressions behind placeholders
494 directly, just make sure not to use "^" and "$" or capturing groups
495 "(...)", because placeholders become part of a larger regular
496 expression internally, non-capturing groups "(?:...)" are fine though.
497
498 # /23 -> {controller => 'foo', action => 'bar', number => 23}
499 # /test -> undef
500 $r->get('/:number' => [number => qr/\d+/])->to('foo#bar');
501
502 # /23 -> undef
503 # /test -> {controller => 'foo', action => 'bar', name => 'test'}
504 $r->get('/:name' => [name => qr/[a-zA-Z]+/])->to('foo#bar');
505
506 This way you get easily readable routes and the raw power of regular
507 expressions.
508
509 Placeholder types
510 And if you have multiple routes using restrictive placeholders you can
511 also turn them into placeholder types with "add_type" in
512 Mojolicious::Routes.
513
514 # A type with alternatives
515 $r->add_type(futurama_name => ['bender', 'leela']);
516
517 # /fry -> undef
518 # /bender -> {controller => 'foo', action => 'bar', name => 'bender'}
519 # /leela -> {controller => 'foo', action => 'bar', name => 'leela'}
520 $r->get('/<name:futurama_name>')->to('foo#bar');
521
522 Placeholder types work just like restrictive placeholders, they are
523 just reusable with the "<placeholder:type>" notation.
524
525 # A type adjusting the regular expression
526 $r->add_type(upper => qr/[A-Z]+/);
527
528 # /user/ROOT -> {controller => 'users', action => 'show', name => 'ROOT'}
529 # /user/root -> undef
530 # /user/23 -> undef
531 $r->get('/user/<name:upper>')->to('users#show');
532
533 Some types like "num" are used so commonly that they are available by
534 default.
535
536 # /article/12 -> {controller => 'article', action => 'show', id => 12}
537 # /article/test -> undef
538 $r->get('/article/<id:num>')->to('articles#show');
539
540 For a full list of available placeholder types see also "TYPES" in
541 Mojolicious::Routes.
542
543 Introspection
544 The command Mojolicious::Command::routes can be used from the command
545 line to list all available routes together with names and underlying
546 regular expressions.
547
548 $ ./myapp.pl routes -v
549 /foo/:name .... POST fooname ^/foo/([^/.]+)/?(?:\.([^/]+))?$
550 /bar ..U. * bar ^/bar
551 +/baz ...W GET baz ^/baz/?(?:\.([^/]+))?$
552 /yada .... * yada ^/yada/?(?:\.([^/]+))?$
553
554 Under
555 To share code with multiple nested routes you can use "under" in
556 Mojolicious::Routes::Route, because unlike normal nested routes, the
557 routes generated with it have their own intermediate destination and
558 result in additional dispatch cycles when they match.
559
560 # /foo -> undef
561 # /foo/bar -> {controller => 'foo', action => 'baz'}
562 # {controller => 'foo', action => 'bar'}
563 my $foo = $r->under('/foo')->to('foo#baz');
564 $foo->get('/bar')->to('#bar');
565
566 The actual action code for this destination needs to return a true
567 value or the dispatch chain will be broken, this can be a very powerful
568 tool for authentication.
569
570 # /blackjack -> {cb => sub {...}}
571 # {controller => 'hideout', action => 'blackjack'}
572 my $auth = $r->under('/' => sub ($c) {
573
574 # Authenticated
575 return 1 if $c->req->headers->header('X-Bender');
576
577 # Not authenticated
578 $c->render(text => "You're not Bender.", status => 401);
579 return undef;
580 });
581 $auth->get('/blackjack')->to('hideout#blackjack');
582
583 Broken dispatch chains can be continued by calling "continue" in
584 Mojolicious::Controller, this allows for example, non-blocking
585 operations to finish before reaching the next dispatch cycle.
586
587 my $maybe = $r->under('/maybe' => sub ($c) {
588
589 # Wait 3 seconds and then give visitors a 50% chance to continue
590 Mojo::IOLoop->timer(3 => sub {
591
592 # Loser
593 return $c->render(text => 'No luck.') unless int rand 2;
594
595 # Winner
596 $c->continue;
597 });
598
599 return undef;
600 });
601 $maybe->get('/')->to('maybe#winner');
602
603 Every destination is just a snapshot of the stash at the time the route
604 matched, and only the "format" value is shared by all of them. For a
605 little more power you can introspect the preceding and succeeding
606 destinations with "match" in Mojolicious::Controller.
607
608 # Action of the fourth dispatch cycle
609 my $action = $c->match->stack->[3]{action};
610
611 Formats
612 File extensions like ".html" and ".txt" at the end of a route are
613 automatically detected and stored in the stash value "format".
614
615 # /foo -> {controller => 'foo', action => 'bar'}
616 # /foo.html -> {controller => 'foo', action => 'bar', format => 'html'}
617 # /foo.txt -> {controller => 'foo', action => 'bar', format => 'txt'}
618 $r->get('/foo')->to('foo#bar');
619
620 This for example, allows multiple templates in different formats to
621 share the same action code. Restrictive placeholders can also be used
622 to limit the allowed formats.
623
624 # /foo.txt -> undef
625 # /foo.rss -> {controller => 'foo', action => 'bar', format => 'rss'}
626 # /foo.xml -> {controller => 'foo', action => 'bar', format => 'xml'}
627 $r->get('/foo' => [format => ['rss', 'xml']])->to('foo#bar');
628
629 A "format" value can also be passed to "url_for" in
630 Mojolicious::Controller.
631
632 # /foo/23.txt -> {controller => 'foo', action => 'bar', id => 23, format => 'txt'}
633 $r->get('/foo/:id')->to('foo#bar')->name('baz');
634
635 # Generate URL "/foo/24.txt" for route "baz"
636 my $url = $c->url_for('baz', id => 24, format => 'txt');
637
638 Or you can just disable format detection with a special type of
639 restrictive placeholder, which gets inherited by nested routes, and
640 then re-enable it on demand.
641
642 # /foo -> {controller => 'foo', action => 'bar'}
643 # /foo.html -> undef
644 $r->get('/foo' => [format => 0])->to('foo#bar');
645
646 # /foo -> {controller => 'foo', action => 'bar'}
647 # /foo.html -> undef
648 # /baz -> undef
649 # /baz.txt -> {controller => 'baz', action => 'yada', format => 'txt'}
650 # /baz.html -> {controller => 'baz', action => 'yada', format => 'html'}
651 # /baz.xml -> undef
652 my $inactive = $r->under([format => 0]);
653 $inactive->get('/foo')->to('foo#bar');
654 $inactive->get('/baz' => [format => ['txt', 'html']])->to('baz#yada');
655
656 WebSockets
657 With the method "websocket" in Mojolicious::Routes::Route you can
658 restrict access to WebSocket handshakes, which are normal "GET"
659 requests with some additional information.
660
661 # /echo (WebSocket handshake)
662 $r->websocket('/echo')->to('foo#echo');
663
664 # Controller
665 package MyApp::Controller::Foo;
666 use Mojo::Base 'Mojolicious::Controller', -signatures;
667
668 # Action
669 sub echo ($self) {
670 $self->on(message => sub ($self, $msg) {
671 $self->send("echo: $msg");
672 });
673 }
674
675 1;
676
677 The connection gets established when you respond to the WebSocket
678 handshake request with a 101 response status, which happens
679 automatically if you subscribe to an event with "on" in
680 Mojolicious::Controller or send a message with "send" in
681 Mojolicious::Controller right away.
682
683 GET /echo HTTP/1.1
684 Host: mojolicious.org
685 User-Agent: Mojolicious (Perl)
686 Connection: Upgrade
687 Upgrade: websocket
688 Sec-WebSocket-Key: IDM3ODE4NDk2MjA1OTcxOQ==
689 Sec-WebSocket-Version: 13
690
691 HTTP/1.1 101 Switching Protocols
692 Server: Mojolicious (Perl)
693 Date: Tue, 03 Feb 2015 17:08:24 GMT
694 Connection: Upgrade
695 Upgrade: websocket
696 Sec-WebSocket-Accept: SWsp5N2iNxPbHlcOTIw8ERvyVPY=
697
698 Catch-all route
699 Since routes match in the order in which they were defined, you can
700 catch all requests that did not match in your last route with an
701 optional wildcard placeholder.
702
703 # * /*
704 $r->any('/*whatever' => {whatever => ''} => sub ($c) {
705 my $whatever = $c->param('whatever');
706 $c->render(text => "/$whatever did not match.", status => 404);
707 });
708
709 Conditions
710 Conditions such as "headers", "agent" and "host" from
711 Mojolicious::Plugin::HeaderCondition can be applied to any route with
712 the method "requires" in Mojolicious::Routes::Route, and allow even
713 more powerful route constructs.
714
715 # / (Origin: http://perl.org)
716 $r->get('/')->requires(headers => {Origin => qr/perl\.org/})->to('foo#bar');
717
718 # / (Firefox)
719 $r->get('/')->requires(agent => qr/Firefox/)->to('browser-test#firefox');
720
721 # / (Internet Explorer)
722 $r->get('/')->requires(agent => qr/Internet Explorer/)->to('browser-test#ie');
723
724 # http://docs.mojolicious.org/Mojolicious
725 $r->get('/')->requires(host => 'docs.mojolicious.org')->to('perldoc#index');
726
727 Just be aware that conditions are too complex for the routing cache,
728 which normally speeds up recurring requests, and can therefore reduce
729 performance.
730
731 Hooks
732 Hooks operate outside the routing system and allow you to extend the
733 framework itself by sharing code with all requests indiscriminately
734 through "hook" in Mojolicious, which makes them a very powerful tool
735 especially for plugins.
736
737 # Application
738 package MyApp;
739 use Mojo::Base 'Mojolicious', -signatures;
740
741 sub startup ($self) {
742
743 # Check all requests for a "/test" prefix
744 $self->hook(before_dispatch => sub ($c) {
745 $c->render(text => 'This request did not reach the router.') if $c->req->url->path->contains('/test');
746 });
747
748 # These will not be reached if the hook above renders a response
749 my $r = $self->routes;
750 $r->get('/welcome')->to('foo#welcome');
751 $r->post('/bye')->to('foo#bye');
752 }
753
754 1;
755
756 Post-processing the response to add or remove headers is a very common
757 use.
758
759 # Make sure static files are cached
760 $app->hook(after_static => sub ($c) {
761 $c->res->headers->cache_control('max-age=3600, must-revalidate');
762 });
763
764 # Remove a default header
765 $app->hook(after_dispatch => sub ($c) {
766 $c->res->headers->remove('Server');
767 });
768
769 Same for pre-processing the request.
770
771 # Choose template variant based on request headers
772 $app->hook(before_dispatch => sub ($c) {
773 return unless my $agent = $c->req->headers->user_agent;
774 $c->stash(variant => 'ie') if $agent =~ /Internet Explorer/;
775 });
776
777 Or more advanced extensions to add monitoring to your application.
778
779 # Forward exceptions to a web service
780 $app->hook(after_dispatch => sub ($c) {
781 return unless my $e = $c->stash('exception');
782 $c->ua->post('https://example.com/bugs' => form => {exception => $e});
783 });
784
785 You can even extend much of the core functionality.
786
787 # Make controller object available to actions as $_
788 $app->hook(around_action => sub ($next, $c, $action, $last) {
789 local $_ = $c;
790 return $next->();
791 });
792
793 # Pass route name as argument to actions
794 $app->hook(around_action => sub ($next, $c, $action, $last) {
795 return $c->$action($c->current_route);
796 });
797
798 For a full list of available hooks see "HOOKS" in Mojolicious.
799
801 Less commonly used and more powerful features.
802
803 Shortcuts
804 To make route generation more expressive, you can also add your own
805 shortcuts with "add_shortcut" in Mojolicious::Routes.
806
807 # Simple "resource" shortcut
808 $r->add_shortcut(resource => sub ($r, $name) {
809
810 # Prefix for resource
811 my $resource = $r->any("/$name")->to("$name#");
812
813 # Render a list of resources
814 $resource->get('/')->to('#index')->name($name);
815
816 # Render a form to create a new resource (submitted to "store")
817 $resource->get('/create')->to('#create')->name("create_$name");
818
819 # Store newly created resource (submitted by "create")
820 $resource->post->to('#store')->name("store_$name");
821
822 # Render a specific resource
823 $resource->get('/:id')->to('#show')->name("show_$name");
824
825 # Render a form to edit a resource (submitted to "update")
826 $resource->get('/:id/edit')->to('#edit')->name("edit_$name");
827
828 # Store updated resource (submitted by "edit")
829 $resource->put('/:id')->to('#update')->name("update_$name");
830
831 # Remove a resource
832 $resource->delete('/:id')->to('#remove')->name("remove_$name");
833
834 return $resource;
835 });
836
837 # GET /users -> {controller => 'users', action => 'index'}
838 # GET /users/create -> {controller => 'users', action => 'create'}
839 # POST /users -> {controller => 'users', action => 'store'}
840 # GET /users/23 -> {controller => 'users', action => 'show', id => 23}
841 # GET /users/23/edit -> {controller => 'users', action => 'edit', id => 23}
842 # PUT /users/23 -> {controller => 'users', action => 'update', id => 23}
843 # DELETE /users/23 -> {controller => 'users', action => 'remove', id => 23}
844 $r->resource('users');
845
846 Rearranging routes
847 From application startup until the first request has arrived, all
848 routes can still be moved around or even removed with methods like
849 "add_child" in Mojolicious::Routes::Route and "remove" in
850 Mojolicious::Routes::Route.
851
852 # GET /example/show -> {controller => 'example', action => 'show'}
853 my $show = $r->get('/show')->to('example#show');
854 $r->any('/example')->add_child($show);
855
856 # Nothing
857 $r->get('/secrets/show')->to('secrets#show')->name('show_secrets');
858 $r->find('show_secrets')->remove;
859
860 Especially for rearranging routes created by plugins this can be very
861 useful, to find routes by their name you can use "find" in
862 Mojolicious::Routes::Route.
863
864 # GET /example/test -> {controller => 'example', action => 'test'}
865 $r->get('/something/else')->to('something#else')->name('test');
866 my $test = $r->find('test');
867 $test->pattern->parse('/example/test');
868 $test->pattern->defaults({controller => 'example', action => 'test'});
869
870 Even the route pattern and destination can still be changed with
871 "parse" in Mojolicious::Routes::Pattern and "defaults" in
872 Mojolicious::Routes::Pattern.
873
874 Adding conditions
875 You can also add your own conditions with the method "add_condition" in
876 Mojolicious::Routes. All conditions are basically router plugins that
877 run every time a new request arrives, and which need to return a true
878 value for the route to match.
879
880 # A condition that randomly allows a route to match
881 $r->add_condition(random => sub ($route, $c, $captures, $num) {
882
883 # Loser
884 return undef if int rand $num;
885
886 # Winner
887 return 1;
888 });
889
890 # /maybe (25% chance)
891 $r->get('/maybe')->requires(random => 4)->to('foo#bar');
892
893 Use whatever request information you need.
894
895 # A condition to check query parameters (useful for mock web services)
896 $r->add_condition(query => sub ($route, $c, $captures, $hash) {
897
898 for my $key (keys %$hash) {
899 my $param = $c->req->url->query->param($key);
900 return undef unless defined $param && $param eq $hash->{$key};
901 }
902
903 return 1;
904 });
905
906 # /hello?to=world&test=1
907 $r->get('/hello')->requires(query => {test => 1, to => 'world'})->to('foo#bar');
908
909 Condition plugins
910 You can also package your conditions as reusable plugins.
911
912 # Plugin
913 package Mojolicious::Plugin::WerewolfCondition;
914 use Mojo::Base 'Mojolicious::Plugin', -signatures;
915
916 use Astro::MoonPhase;
917
918 sub register ($self, $app, $conf) {
919
920 # Add "werewolf" condition
921 $app->routes->add_condition(werewolf => sub ($route, $c, $captures, $days) {
922
923 # Keep the werewolves out!
924 return undef if abs(14 - (phase(time))[2]) > ($days / 2);
925
926 # It's ok, no werewolf
927 return 1;
928 });
929 }
930
931 1;
932
933 Now just load the plugin and you are ready to use the condition in all
934 your applications.
935
936 # Application
937 package MyApp;
938 use Mojo::Base 'Mojolicious', -signatures;
939
940 sub startup ($self) {
941
942 # Plugin
943 $self->plugin('WerewolfCondition');
944
945 # /hideout (keep them out for 4 days after full moon)
946 $self->routes->get('/hideout')->requires(werewolf => 4)->to(controller => 'foo', action => 'bar');
947 }
948
949 1;
950
951 Mount applications
952 The easiest way to embed one application into another is
953 Mojolicious::Plugin::Mount, which allows you to mount whole self-
954 contained applications under a domain and/or prefix.
955
956 use Mojolicious::Lite -signatures;
957
958 # Whole application mounted under "/prefix"
959 plugin Mount => {'/prefix' => '/home/sri/myapp/script/myapp'};
960
961 # Mount application with subdomain
962 plugin Mount => {'test.example.com' => '/home/sri/myapp2.pl'};
963
964 # Normal route
965 get '/' => sub ($c) {
966 $c->render(text => 'Hello World!');
967 };
968
969 app->start;
970
971 Embed applications
972 For a little more power you can also embed applications by using them
973 instead of a controller. This allows for example, the use of the
974 Mojolicious::Lite domain specific language in normal Mojolicious
975 controllers.
976
977 # Controller
978 package MyApp::Controller::Bar;
979 use Mojolicious::Lite -signatures;
980
981 # /hello
982 get '/hello' => sub ($c) {
983 my $name = $c->param('name');
984 $c->render(text => "Hello $name.");
985 };
986
987 1;
988
989 With the attribute "partial" in Mojolicious::Routes::Route, you can
990 allow the route to partially match and use only the remaining path in
991 the embedded application, the base path will be passed along in the
992 "path" stash value.
993
994 # /foo/*
995 $r->any('/foo')->partial(1)->to('bar#', name => 'Mojo');
996
997 A minimal embeddable application is nothing more than a subclass of
998 Mojolicious, containing a "handler" method accepting
999 Mojolicious::Controller objects.
1000
1001 package MyApp::Controller::Bar;
1002 use Mojo::Base 'Mojolicious', -signatures;
1003
1004 sub handler ($self, $c) {
1005 $c->res->code(200);
1006 my $name = $c->param('name');
1007 $c->res->body("Hello $name.");
1008 }
1009
1010 1;
1011
1012 The host application will only share very little information with the
1013 embedded application through the stash. So you cannot currently use
1014 route placeholders in routes leading to embedded applications, since
1015 that would cause problems with "url_for" in Mojolicious::Controller.
1016
1017 Application plugins
1018 You can even package applications as self-contained reusable plugins.
1019
1020 # Plugin
1021 package Mojolicious::Plugin::MyEmbeddedApp;
1022 use Mojo::Base 'Mojolicious::Plugin', -signatures;
1023
1024 sub register ($self, $app, $conf) {
1025
1026 # Automatically add route
1027 $app->routes->any('/foo')->partial(1)->to(app => EmbeddedApp::app());
1028 }
1029
1030 package EmbeddedApp;
1031 use Mojolicious::Lite;
1032
1033 get '/bar' => 'bar';
1034
1035 1;
1036 __DATA__
1037 @@ bar.html.ep
1038 Hello World!
1039
1040 The "app" stash value, which won't be inherited by nested routes, can
1041 be used for already instantiated applications. Now just load the
1042 plugin and you're done.
1043
1044 # Application
1045 package MyApp;
1046 use Mojo::Base 'Mojolicious', -signatures;
1047
1048 sub startup ($self) {
1049
1050 # Plugin
1051 $self->plugin('MyEmbeddedApp');
1052 }
1053
1054 1;
1055
1057 You can continue with Mojolicious::Guides now or take a look at the
1058 Mojolicious wiki <https://github.com/mojolicious/mojo/wiki>, which
1059 contains a lot more documentation and examples by many different
1060 authors.
1061
1063 If you have any questions the documentation might not yet answer, don't
1064 hesitate to ask in the Forum <https://forum.mojolicious.org> or the
1065 official IRC channel "#mojo" on "chat.freenode.net" (chat now!
1066 <https://webchat.freenode.net/#mojo>).
1067
1068
1069
1070perl v5.32.1 2021-02-07 Mojolicious::Guides::Routing(3)