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