Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
Mojolicious::Guides::RUsernContributed Perl DocMojolicious::Guides::Routing(3)

NAME
       Mojolicious::Guides::Routing - Routing requests

OVERVIEW
       This document contains a	simple and fun introduction to the Mojolicious
       router and its underlying concepts.

CONCEPTS
       Essentials every	Mojolicious developer should know.

   Dispatcher
       The foundation of every web framework is	a tiny black box connecting
       incoming	requests with code generating the appropriate response.

	 GET /user/show/1 -> $c->render(text =>	'Daniel');

       This black box is usually called	a dispatcher. There are	many
       implementations using different strategies to establish these
       connections, but	pretty much all	are based around mapping the path part
       of the request URL to some kind of response generator.

	 /user/show/2 -> $c->render(text => 'Isabell');
	 /user/show/3 -> $c->render(text => 'Sara');
	 /user/show/4 -> $c->render(text => 'Stefan');
	 /user/show/5 -> $c->render(text => 'Fynn');

       While it	is very	well possible to make all these	connections static, it
       is also rather inefficient. That's why regular expressions are commonly
       used to make the	dispatch process more dynamic.

	 qr!/user/show/(\d+)! -> $c->render(text => $users{$1});

       Modern dispatchers have pretty much everything HTTP has to offer	at
       their disposal and can use many more variables than just	the request
       path, such as request method and	headers	like "Host", "User-Agent" and
       "Accept".

	 GET /user/show/23 HTTP/1.1
	 Host: mojolicious.org
	 User-Agent: Mojolicious (Perl)
	 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

   Routes
       While regular expressions are quite powerful they also tend to be
       unpleasant to look at and are generally overkill	for ordinary path
       matching.

	 qr!/user/show/(\d+)! -> $c->render(text => $users{$1});

       This is where routes come into play, they have been designed from the
       ground up to represent paths with placeholders.

	 /user/show/:id	-> $c->render(text => $users{$id});

       The only	difference between a static path and the route above is	the
       ":id" placeholder. One or more placeholders can be anywhere in the
       route.

	 /user/:action/:id

       A fundamental concept of	the Mojolicious	router is that extracted
       placeholder values are turned into a hash.

	 /user/show/23 -> /user/:action/:id -> {action => 'show', id =>	23}

       This hash is basically the center of every Mojolicious application, you
       will learn more about this later	on.  Internally, routes	get compiled
       to regular expressions, so you can get the best of both worlds with a
       little bit of experience.

	 /user/show/:id	-> qr/(?-xism:^\/user\/show\/([^\/.]+))/

       A trailing slash	in the path is always optional.

	 /user/show/23/	-> /user/:action/:id ->	{action	=> 'show', id => 23}

   Reversibility
       One more	huge advantage routes have over	regular	expressions is that
       they are	easily reversible, extracted placeholders can be turned	back
       into a path at any time.

	 /sebastian -> /:name -> {name => 'sebastian'}
	 {name => 'sebastian'} -> /:name -> /sebastian

       Every placeholder has a name, even if it's just an empty	string.

   Standard placeholders
       Standard	placeholders are the simplest form of placeholders, they use a
       colon prefix and	match all characters except "/"	and ".", similar to
       the regular expression "([^/.]+)".

	 /hello		     ->	/:name/hello ->	undef
	 /sebastian/23/hello ->	/:name/hello ->	undef
	 /sebastian.23/hello ->	/:name/hello ->	undef
	 /sebastian/hello    ->	/:name/hello ->	{name => 'sebastian'}
	 /sebastian23/hello  ->	/:name/hello ->	{name => 'sebastian23'}
	 /sebastian 23/hello ->	/:name/hello ->	{name => 'sebastian 23'}

       All placeholders	can be surrounded by "<" and ">" to separate them from
       the surrounding text.

	 /hello		    -> /<:name>hello ->	undef
	 /sebastian/23hello -> /<:name>hello ->	undef
	 /sebastian.23hello -> /<:name>hello ->	undef
	 /sebastianhello    -> /<:name>hello ->	{name => 'sebastian'}
	 /sebastian23hello  -> /<:name>hello ->	{name => 'sebastian23'}
	 /sebastian 23hello -> /<:name>hello ->	{name => 'sebastian 23'}

       The colon prefix	is optional for	standard placeholders that are
       surrounded by "<" and ">".

	 /iaYmojolicious -> /<one>aY<two> -> {one => 'i', two => 'mojolicious'}

   Relaxed placeholders
       Relaxed placeholders are	just like standard placeholders, but use a
       hash prefix and match all characters except "/",	similar	to the regular
       expression "([^/]+)".

	 /hello		     ->	/#name/hello ->	undef
	 /sebastian/23/hello ->	/#name/hello ->	undef
	 /sebastian.23/hello ->	/#name/hello ->	{name => 'sebastian.23'}
	 /sebastian/hello    ->	/#name/hello ->	{name => 'sebastian'}
	 /sebastian23/hello  ->	/#name/hello ->	{name => 'sebastian23'}
	 /sebastian 23/hello ->	/#name/hello ->	{name => 'sebastian 23'}

       They can	be especially useful for manually matching file	names with
       extensions, rather than using format detection.

	 /music/song.mp3 -> /music/#filename ->	{filename => 'song.mp3'}

   Wildcard placeholders
       Wildcard	placeholders are just like the two types of placeholders
       above, but use an asterisk prefix and match absolutely everything,
       including "/" and ".", similar to the regular expression	"(.+)".

	 /hello		     ->	/*name/hello ->	undef
	 /sebastian/23/hello ->	/*name/hello ->	{name => 'sebastian/23'}
	 /sebastian.23/hello ->	/*name/hello ->	{name => 'sebastian.23'}
	 /sebastian/hello    ->	/*name/hello ->	{name => 'sebastian'}
	 /sebastian23/hello  ->	/*name/hello ->	{name => 'sebastian23'}
	 /sebastian 23/hello ->	/*name/hello ->	{name => 'sebastian 23'}

       They can	be useful for manually matching	entire file paths.

	 /music/rock/song.mp3 -> /music/*filepath -> {filepath => 'rock/song.mp3'}

BASICS
       Most commonly used features every Mojolicious developer should know
       about.

   Minimal route
       The attribute "routes" in Mojolicious contains a	router you can use to
       generate	route structures.

	 # Application
	 package MyApp;
	 use Mojo::Base	'Mojolicious', -signatures;

	 sub startup ($self) {
	   # Router
	   my $r = $self->routes;

	   # Route
	   $r->get('/welcome')->to(controller => 'foo',	action => 'welcome');
	 }

	 1;

       The minimal route above will load and instantiate the class
       "MyApp::Controller::Foo"	and call its "welcome" method.	Routes are
       usually configured in the "startup" method of the application class,
       but the router can be accessed from everywhere (even at runtime).

	 # Controller
	 package MyApp::Controller::Foo;
	 use Mojo::Base	'Mojolicious::Controller', -signatures;

	 # Action
	 sub welcome ($self) {
	   # Render response
	   $self->render(text => 'Hello	there.');
	 }

	 1;

       All routes match	in the same order in which they	were defined, and
       matching	stops as soon as a suitable route has been found. So you can
       improve the routing performance by declaring your most frequently
       accessed	routes first. A	routing	cache will also	be used	automatically
       to handle sudden	traffic	spikes more gracefully.

   Routing destination
       After you start a new route with	methods	like "get" in
       Mojolicious::Routes::Route, you can also	give it	a destination in the
       form of a hash using the	chained	method "to" in
       Mojolicious::Routes::Route.

	 # /welcome -> {controller => 'foo', action => 'welcome'}
	 $r->get('/welcome')->to(controller => 'foo', action =>	'welcome');

       Now if the route	matches	an incoming request it will use	the content of
       this hash to try	and find appropriate code to generate a	response.

   HTTP	methods
       There are already shortcuts for the most	common HTTP request methods
       like "post" in Mojolicious::Routes::Route, and for more control "any"
       in Mojolicious::Routes::Route accepts an	optional array reference with
       arbitrary request methods as first argument.

	 # PUT /hello  -> undef
	 # GET /hello  -> {controller => 'foo',	action => 'hello'}
	 $r->get('/hello')->to(controller => 'foo', action => 'hello');

	 # PUT /hello -> {controller =>	'foo', action => 'hello'}
	 $r->put('/hello')->to(controller => 'foo', action => 'hello');

	 # POST	/hello -> {controller => 'foo',	action => 'hello'}
	 $r->post('/hello')->to(controller => 'foo', action => 'hello');

	 # GET|POST /bye  -> {controller => 'foo', action => 'bye'}
	 $r->any(['GET', 'POST'] => '/bye')->to(controller => 'foo', action => 'bye');

	 # * /whatever -> {controller => 'foo',	action => 'whatever'}
	 $r->any('/whatever')->to(controller =>	'foo', action => 'whatever');

       There is	one small exception, "HEAD" requests are considered equal to
       "GET", but content will not be sent with	the response even if it	is
       present.

	 # GET /test  -> {controller =>	'bar', action => 'test'}
	 # HEAD	/test -> {controller =>	'bar', action => 'test'}
	 $r->get('/test')->to(controller => 'bar', action => 'test');

       You can also use	the "_method" query parameter to override the request
       method. This can	be very	useful when submitting forms with browsers
       that only support "GET" and "POST".

	 # PUT	/stuff		   -> {controller => 'baz', action => 'stuff'}
	 # POST	/stuff?_method=PUT -> {controller => 'baz', action => 'stuff'}
	 $r->put('/stuff')->to(controller => 'baz', action => 'stuff');

   IRIs
       IRIs are	handled	transparently, that means paths	are guaranteed to be
       unescaped and decoded from bytes	to characters.

	 # GET /a (Unicode snowman) -> {controller => 'foo', action => 'snowman'}
	 $r->get('/a')->to(controller => 'foo',	action => 'snowman');

   Stash
       The generated hash of a matching	route is actually the center of	the
       whole Mojolicious request cycle.	We call	it the stash, and it persists
       until a response	has been generated.

	 # /bye	-> {controller => 'foo', action	=> 'bye', mymessage => 'Bye'}
	 $r->get('/bye')->to(controller	=> 'foo', action => 'bye', mymessage =>	'Bye');

       There are a few stash values with special meaning, such as "controller"
       and "action", but you can generally fill	it with	whatever data you need
       to generate a response. Once dispatched the whole stash content can be
       changed at any time.

	 sub bye ($self) {

	   # Get message from stash
	   my $msg = $self->stash('mymessage');

	   # Change message in stash
	   $self->stash(mymessage => 'Welcome');
	 }

       For a full list of reserved stash values	see "stash" in
       Mojolicious::Controller.

   Nested routes
       It is also possible to build tree structures from routes	to remove
       repetitive code.	A route	with children can't match on its own though,
       only the	actual endpoints of these nested routes	can.

	 # /foo	    -> undef
	 # /foo/bar -> {controller => 'foo', action => 'bar'}
	 my $foo = $r->any('/foo')->to(controller => 'foo');
	 $foo->get('/bar')->to(action => 'bar');

       The stash is simply inherited from route	to route and newer values
       override	old ones.

	 # /cats      -> {controller =>	'cats',	action => 'index'}
	 # /cats/nyan -> {controller =>	'cats',	action => 'nyan'}
	 # /cats/lol  -> {controller =>	'cats',	action => 'default'}
	 my $cats = $r->any('/cats')->to(controller => 'cats', action => 'default');
	 $cats->get('/')->to(action => 'index');
	 $cats->get('/nyan')->to(action	=> 'nyan');
	 $cats->get('/lol');

       With a few common prefixes you can also greatly improve the routing
       performance of applications with	many routes, because children are only
       tried if	the prefix matched first.

   Special stash values
       When the	dispatcher sees	"controller" and "action" values in the	stash
       it will always try to turn them into a class and	method to dispatch to.
       The "controller"	value gets converted from "snake_case" to "CamelCase"
       using "camelize"	in Mojo::Util and appended to one or more namespaces,
       defaulting to a controller namespace based on the application class
       ("MyApp::Controller"), as well as the bare application class ("MyApp"),
       and these namespaces are	searched in that order.	The action value is
       not changed at all, so both values are case-sensitive.

	 # Application
	 package MyApp;
	 use Mojo::Base	'Mojolicious', -signatures;

	 sub startup ($self) {
	   # /bye -> MyApp::Controller::Foo->bye
	   $self->routes->get('/bye')->to(controller =>	'foo', action => 'bye');
	 }

	 1;

	 # Controller
	 package MyApp::Controller::Foo;
	 use Mojo::Base	'Mojolicious::Controller', -signatures;

	 # Action
	 sub bye ($self) {
	   # Render response
	   $self->render(text => 'Good bye.');
	 }

	 1;

       Controller classes are perfect for organizing code in larger projects.
       There are more dispatch strategies, but because controllers are the
       most commonly used ones they also got a special shortcut	in the form of
       "controller#action".

	 # /bye	-> {controller => 'foo', action	=> 'bye', mymessage => 'Bye'}
	 $r->get('/bye')->to('foo#bye',	mymessage => 'Bye');

       During camelization "-" characters get replaced with "::", this allows
       multi-level "controller"	hierarchies.

	 # / ->	MyApp::Controller::Foo::Bar->hi
	 $r->get('/')->to('foo-bar#hi');

       You can also just specify the "controller" in CamelCase form instead of
       snake_case.

	 # / ->	MyApp::Controller::Foo::Bar->hi
	 $r->get('/')->to('Foo::Bar#hi');

       For security reasons the	dispatcher will	always check if	the
       "controller" is actually	a subclass of Mojolicious::Controller or Mojo
       before dispatching to it.

   Namespaces
       You can use the "namespace" stash value to change the namespace of a
       whole route with	all its	children.

	 # /bye	-> MyApp::MyController::Foo::Bar->bye
	 $r->get('/bye')->to(namespace => 'MyApp::MyController::Foo::Bar', action => 'bye');

       The "controller"	is always converted from "snake_case" to "CamelCase"
       with "camelize" in Mojo::Util, and then appended	to this	"namespace".

	 # /bye	-> MyApp::MyController::Foo::Bar->bye
	 $r->get('/bye')->to('foo-bar#bye', namespace => 'MyApp::MyController');

	 # /hey	-> MyApp::MyController::Foo::Bar->hey
	 $r->get('/hey')->to('Foo::Bar#hey', namespace => 'MyApp::MyController');

       You can also change the default namespaces for all routes in the
       application with	the router attribute "namespaces" in
       Mojolicious::Routes, which usually defaults to a	namespace based	on the
       application class ("MyApp::Controller"),	as well	as the bare
       application class ("MyApp").

	 $r->namespaces(['MyApp::MyController']);

   Route to callback
       The "cb"	stash value, which won't be inherited by nested	routes,	can be
       used to bypass controllers and execute a	callback instead.

	 $r->get('/bye')->to(cb	=> sub ($c) {
	   $c->render(text => 'Good bye.');
	 });

       But just	like in	Mojolicious::Lite you can also pass the	callback
       directly, which usually looks much better.

	 $r->get('/bye'	=> sub ($c) {
	   $c->render(text => 'Good bye.');
	 });

   Named routes
       Naming your routes will allow backreferencing in	many methods and
       helpers throughout the whole framework, most of which internally	rely
       on "url_for" in Mojolicious::Controller for this.

	 # /foo/marcus -> {controller => 'foo',	action => 'bar', user => 'marcus'}
	 $r->get('/foo/:user')->to('foo#bar')->name('baz');

	 # Generate URL	"/foo/marcus" for route	"baz" (in previous request context)
	 my $url = $c->url_for('baz');

	 # Generate URL	"/foo/jan" for route "baz"
	 my $url = $c->url_for('baz', user => 'jan');

	 # Generate URL	"http://127.0.0.1:3000/foo/jan"	for route "baz"
	 my $url = $c->url_for('baz', user => 'jan')->to_abs;

       You can assign a	name with "name" in Mojolicious::Routes::Route,	or let
       the router generate one automatically, which would be equal to the
       route itself without non-word characters, custom	names have a higher
       precedence though.

	 # /foo/bar ("foobar")
	 $r->get('/foo/bar')->to('test#stuff');

	 # Generate URL	"/foo/bar"
	 my $url = $c->url_for('foobar');

       To refer	to the current route you can use the reserved name "current"
       or no name at all.

	 # Generate URL	for current route
	 my $url = $c->url_for('current');
	 my $url = $c->url_for;

       To check	or get the name	of the current route you can use the helper
       "current_route" in Mojolicious::Plugin::DefaultHelpers.

	 # Name	for current route
	 my $name = $c->current_route;

	 # Check route name in code shared by multiple routes
	 $c->stash(button => 'green') if $c->current_route('login');

   Optional placeholders
       Extracted placeholder values will simply	redefine older stash values if
       they already exist.

	 # /bye	-> {controller => 'foo', action	=> 'bar', mymessage => 'bye'}
	 # /hey	-> {controller => 'foo', action	=> 'bar', mymessage => 'hey'}
	 $r->get('/:mymessage')->to('foo#bar', mymessage => 'hi');

       One more	interesting effect, a placeholder automatically	becomes
       optional	if there is already a stash value of the same name present,
       this works similar to the regular expression "([^/.]+)?".

	 # / ->	{controller => 'foo', action =>	'bar', mymessage => 'hi'}
	 $r->get('/:mymessage')->to('foo#bar', mymessage => 'hi');

	 # /test/123	 -> {controller	=> 'foo', action => 'bar', mymessage =>	'hi'}
	 # /test/bye/123 -> {controller	=> 'foo', action => 'bar', mymessage =>	'bye'}
	 $r->get('/test/:mymessage/123')->to('foo#bar',	mymessage => 'hi');

       And if two optional placeholders	are only separated by a	slash, that
       slash can become	optional as well.

	 # /	       -> {controller => 'foo',	  action => 'bar'}
	 # /users      -> {controller => 'users', action => 'bar'}
	 # /users/list -> {controller => 'users', action => 'list'}
	 $r->get('/:controller/:action')->to('foo#bar');

       Special stash values like "controller" and "action" can also be
       placeholders, which is very convenient especially during	development,
       but should only be used very carefully, because every controller	method
       becomes a potential route.  All uppercase methods as well as those
       starting	with an	underscore are automatically hidden from the router
       and you can use "hide" in Mojolicious::Routes to	add additional ones.

	 # Hide	"create" method	in all controllers
	 $r->hide('create');

       This has	already	been done for all attributes and methods from
       Mojolicious::Controller.

   Restrictive placeholders
       A very easy way to make placeholders more restrictive are alternatives,
       you just	make a list of possible	values,	which then work	similar	to the
       regular expression "(bender|leela)".

	 # /fry	   -> undef
	 # /bender -> {controller => 'foo', action => 'bar', name => 'bender'}
	 # /leela  -> {controller => 'foo', action => 'bar', name => 'leela'}
	 $r->get('/:name' => [name => ['bender', 'leela']])->to('foo#bar');

       You can also adjust the regular expressions behind placeholders
       directly, just make sure	not to use "^" and "$" or capturing groups
       "(...)",	because	placeholders become part of a larger regular
       expression internally, non-capturing groups "(?:...)" are fine though.

	 # /23	 -> {controller	=> 'foo', action => 'bar', number => 23}
	 # /test -> undef
	 $r->get('/:number' => [number => qr/\d+/])->to('foo#bar');

	 # /23	 -> undef
	 # /test -> {controller	=> 'foo', action => 'bar', name	=> 'test'}
	 $r->get('/:name' => [name => qr/[a-zA-Z]+/])->to('foo#bar');

       This way	you get	easily readable	routes and the raw power of regular
       expressions.

   Placeholder types
       And if you have multiple	routes using restrictive placeholders you can
       also turn them into placeholder types with "add_type" in
       Mojolicious::Routes.

	 # A type with alternatives
	 $r->add_type(futurama_name => ['bender', 'leela']);

	 # /fry	   -> undef
	 # /bender -> {controller => 'foo', action => 'bar', name => 'bender'}
	 # /leela  -> {controller => 'foo', action => 'bar', name => 'leela'}
	 $r->get('/<name:futurama_name>')->to('foo#bar');

       Placeholder types work just like	restrictive placeholders, they are
       just reusable with the "<placeholder:type>" notation.

	 # A type adjusting the	regular	expression
	 $r->add_type(upper => qr/[A-Z]+/);

	 # /user/ROOT -> {controller =>	'users', action	=> 'show', name	=> 'ROOT'}
	 # /user/root -> undef
	 # /user/23   -> undef
	 $r->get('/user/<name:upper>')->to('users#show');

       Some types like "num" are used so commonly that they are	available by
       default.

	 # /article/12	 -> {controller	=> 'article', action =>	'show',	id => 12}
	 # /article/test -> undef
	 $r->get('/article/<id:num>')->to('articles#show');

       For a full list of available placeholder	types see also "TYPES" in
       Mojolicious::Routes.

   Introspection
       The command Mojolicious::Command::routes	can be used from the command
       line to list all	available routes together with names and underlying
       regular expressions.

	 $ ./myapp.pl routes -v
	 /foo/:name  ....  POST	 fooname  ^/foo/([^/.]+)/?(?:\.([^/]+))?$
	 /bar	     ..U.  *	 bar	  ^/bar
	   +/baz     ...W  GET	 baz	  ^/baz/?(?:\.([^/]+))?$
	 /yada	     ....  *	 yada	  ^/yada/?(?:\.([^/]+))?$

   Under
       To share	code with multiple nested routes you can use "under" in
       Mojolicious::Routes::Route, because unlike normal nested	routes,	the
       routes generated	with it	have their own intermediate destination	and
       result in additional dispatch cycles when they match.

	 # /foo	    -> undef
	 # /foo/bar -> {controller => 'foo', action => 'baz'}
	 #	       {controller => 'foo', action => 'bar'}
	 my $foo = $r->under('/foo')->to('foo#baz');
	 $foo->get('/bar')->to('#bar');

       The actual action code for this destination needs to return a true
       value or	the dispatch chain will	be broken, this	can be a very powerful
       tool for	authentication.

	 # /blackjack -> {cb =>	sub {...}}
	 #		 {controller =>	'hideout', action => 'blackjack'}
	 my $auth = $r->under('/' => sub ($c) {

	   # Authenticated
	   return 1 if $c->req->headers->header('X-Bender');

	   # Not authenticated
	   $c->render(text => "You're not Bender.", status => 401);
	   return undef;
	 });
	 $auth->get('/blackjack')->to('hideout#blackjack');

       Broken dispatch chains can be continued by calling "continue" in
       Mojolicious::Controller,	this allows for	example, non-blocking
       operations to finish before reaching the	next dispatch cycle.

	 my $maybe = $r->under('/maybe'	=> sub ($c) {

	   # Wait 3 seconds and	then give visitors a 50% chance	to continue
	   Mojo::IOLoop->timer(3 => sub	{

	     # Loser
	     return $c->render(text => 'No luck.') unless int rand 2;

	     # Winner
	     $c->continue;
	   });

	   return undef;
	 });
	 $maybe->get('/')->to('maybe#winner');

       Every destination is just a snapshot of the stash at the	time the route
       matched,	and only the "format" value is shared by all of	them. For a
       little more power you can introspect the	preceding and succeeding
       destinations with "match" in Mojolicious::Controller.

	 # Action of the fourth	dispatch cycle
	 my $action = $c->match->stack->[3]{action};

   Formats
       File extensions like ".html" and	".txt" at the end of a route are
       automatically detected and stored in the	stash value "format".

	 # /foo	     ->	{controller => 'foo', action =>	'bar'}
	 # /foo.html ->	{controller => 'foo', action =>	'bar', format => 'html'}
	 # /foo.txt  ->	{controller => 'foo', action =>	'bar', format => 'txt'}
	 $r->get('/foo')->to('foo#bar');

       This for	example, allows	multiple templates in different	formats	to
       share the same action code. Restrictive placeholders can	also be	used
       to limit	the allowed formats.

	 # /foo.txt -> undef
	 # /foo.rss -> {controller => 'foo', action => 'bar', format =>	'rss'}
	 # /foo.xml -> {controller => 'foo', action => 'bar', format =>	'xml'}
	 $r->get('/foo'	=> [format => ['rss', 'xml']])->to('foo#bar');

       A "format" value	can also be passed to "url_for"	in
       Mojolicious::Controller.

	 # /foo/bar.txt	-> {controller => 'foo', action	=> 'bar', format => 'txt'}
	 $r->get('/foo/:action')->to('foo#')->name('baz');

	 # Generate URL	"/foo/bar.txt" for route "baz"
	 my $url = $c->url_for('baz', action =>	'bar', format => 'txt');

       Or you can just disable format detection	with a special type of
       restrictive placeholder,	which gets inherited by	nested routes, and
       then re-enable it on demand.

	 # /foo	     ->	{controller => 'foo', action =>	'bar'}
	 # /foo.html ->	undef
	 $r->get('/foo'	=> [format => 0])->to('foo#bar');

	 # /foo	     ->	{controller => 'foo', action =>	'bar'}
	 # /foo.html ->	undef
	 # /baz	     ->	undef
	 # /baz.txt  ->	{controller => 'baz', action =>	'yada',	format => 'txt'}
	 # /baz.html ->	{controller => 'baz', action =>	'yada',	format => 'html'}
	 # /baz.xml  ->	undef
	 my $inactive =	$r->under([format => 0]);
	 $inactive->get('/foo')->to('foo#bar');
	 $inactive->get('/baz' => [format => ['txt', 'html']])->to('baz#yada');

   WebSockets
       With the	method "websocket" in Mojolicious::Routes::Route you can
       restrict	access to WebSocket handshakes,	which are normal "GET"
       requests	with some additional information.

	 # /echo (WebSocket handshake)
	 $r->websocket('/echo')->to('foo#echo');

	 # Controller
	 package MyApp::Controller::Foo;
	 use Mojo::Base	'Mojolicious::Controller', -signatures;

	 # Action
	 sub echo ($self) {
	   $self->on(message =>	sub ($self, $msg) {
	     $self->send("echo:	$msg");
	   });
	 }

	 1;

       The connection gets established when you	respond	to the WebSocket
       handshake request with a	101 response status, which happens
       automatically if	you subscribe to an event with "on" in
       Mojolicious::Controller or send a message with "send" in
       Mojolicious::Controller right away.

	 GET /echo HTTP/1.1
	 Host: mojolicious.org
	 User-Agent: Mojolicious (Perl)
	 Connection: Upgrade
	 Upgrade: websocket
	 Sec-WebSocket-Key: IDM3ODE4NDk2MjA1OTcxOQ==
	 Sec-WebSocket-Version:	13

	 HTTP/1.1 101 Switching	Protocols
	 Server: Mojolicious (Perl)
	 Date: Tue, 03 Feb 2015	17:08:24 GMT
	 Connection: Upgrade
	 Upgrade: websocket
	 Sec-WebSocket-Accept: SWsp5N2iNxPbHlcOTIw8ERvyVPY=

   Catch-all route
       Since routes match in the order in which	they were defined, you can
       catch all requests that did not match in	your last route	with an
       optional	wildcard placeholder.

	 # * /*
	 $r->any('/*whatever' => {whatever => ''} => sub ($c) {
	   my $whatever	= $c->param('whatever');
	   $c->render(text => "/$whatever did not match.", status => 404);
	 });

   Conditions
       Conditions such as "headers", "agent" and "host"	from
       Mojolicious::Plugin::HeaderCondition can	be applied to any route	with
       the method "requires" in	Mojolicious::Routes::Route, and	allow even
       more powerful route constructs.

	 # / (Origin: http://perl.org)
	 $r->get('/')->requires(headers	=> {Origin => qr/perl\.org/})->to('foo#bar');

	 # / (Firefox)
	 $r->get('/')->requires(agent => qr/Firefox/)->to('browser-test#firefox');

	 # / (Internet Explorer)
	 $r->get('/')->requires(agent => qr/Internet Explorer/)->to('browser-test#ie');

	 # http://docs.mojolicious.org/Mojolicious
	 $r->get('/')->requires(host =>	'docs.mojolicious.org')->to('perldoc#index');

       Just be aware that conditions are too complex for the routing cache,
       which normally speeds up	recurring requests, and	can therefore reduce
       performance.

   Hooks
       Hooks operate outside the routing system	and allow you to extend	the
       framework itself	by sharing code	with all requests indiscriminately
       through "hook" in Mojolicious, which makes them a very powerful tool
       especially for plugins.

	 # Application
	 package MyApp;
	 use Mojo::Base	'Mojolicious', -signatures;

	 sub startup ($self) {

	   # Check all requests	for a "/test" prefix
	   $self->hook(before_dispatch => sub ($c) {
	     $c->render(text =>	'This request did not reach the	router.') if $c->req->url->path->contains('/test');
	   });

	   # These will	not be reached if the hook above renders a response
	   my $r = $self->routes;
	   $r->get('/welcome')->to('foo#welcome');
	   $r->post('/bye')->to('foo#bye');
	 }

	 1;

       Post-processing the response to add or remove headers is	a very common
       use.

	 # Make	sure static files are cached
	 $app->hook(after_static => sub	($c) {
	   $c->res->headers->cache_control('max-age=3600, must-revalidate');
	 });

	 # Remove a default header
	 $app->hook(after_dispatch => sub ($c) {
	   $c->res->headers->remove('Server');
	 });

       Same for	pre-processing the request.

	 # Choose template variant based on request headers
	 $app->hook(before_dispatch => sub ($c)	{
	   return unless my $agent = $c->req->headers->user_agent;
	   $c->stash(variant =>	'ie') if $agent	=~ /Internet Explorer/;
	 });

       Or more advanced	extensions to add monitoring to	your application.

	 # Forward exceptions to a web service
	 $app->hook(after_dispatch => sub ($c) {
	   return unless my $e = $c->stash('exception');
	   $c->ua->post('https://example.com/bugs' => form => {exception => $e});
	 });

       You can even extend much	of the core functionality.

	 # Make	controller object available to actions as $_
	 $app->hook(around_action => sub ($next, $c, $action, $last) {
	   local $_ = $c;
	   return $next->();
	 });

	 # Pass	route name as argument to actions
	 $app->hook(around_action => sub ($next, $c, $action, $last) {
	   return $c->$action($c->current_route);
	 });

       For a full list of available hooks see "HOOKS" in Mojolicious.

ADVANCED
       Less commonly used and more powerful features.

   Shortcuts
       To make route generation	more expressive, you can also add your own
       shortcuts with "add_shortcut" in	Mojolicious::Routes.

	 # Simple "resource" shortcut
	 $r->add_shortcut(resource => sub ($r, $name) {

	   # Prefix for	resource
	   my $resource	= $r->any("/$name")->to("$name#");

	   # Render a list of resources
	   $resource->get('/')->to('#index')->name($name);

	   # Render a form to create a new resource (submitted to "store")
	   $resource->get('/create')->to('#create')->name("create_$name");

	   # Store newly created resource (submitted by	"create")
	   $resource->post->to('#store')->name("store_$name");

	   # Render a specific resource
	   $resource->get('/:id')->to('#show')->name("show_$name");

	   # Render a form to edit a resource (submitted to "update")
	   $resource->get('/:id/edit')->to('#edit')->name("edit_$name");

	   # Store updated resource (submitted by "edit")
	   $resource->put('/:id')->to('#update')->name("update_$name");

	   # Remove a resource
	   $resource->delete('/:id')->to('#remove')->name("remove_$name");

	   return $resource;
	 });

	 # GET /users	      -> {controller =>	'users', action	=> 'index'}
	 # GET /users/create  -> {controller =>	'users', action	=> 'create'}
	 # POST	/users	      -> {controller =>	'users', action	=> 'store'}
	 # GET /users/23      -> {controller =>	'users', action	=> 'show', id => 23}
	 # GET /users/23/edit -> {controller =>	'users', action	=> 'edit', id => 23}
	 # PUT /users/23      -> {controller =>	'users', action	=> 'update', id	=> 23}
	 # DELETE /users/23   -> {controller =>	'users', action	=> 'remove', id	=> 23}
	 $r->resource('users');

   Rearranging routes
       From application	startup	until the first	request	has arrived, all
       routes can still	be moved around	or even	removed	with methods like
       "add_child" in Mojolicious::Routes::Route and "remove" in
       Mojolicious::Routes::Route.

	 # GET /example/show ->	{controller => 'example', action => 'show'}
	 my $show = $r->get('/show')->to('example#show');
	 $r->any('/example')->add_child($show);

	 # Nothing
	 $r->get('/secrets/show')->to('secrets#show')->name('show_secrets');
	 $r->find('show_secrets')->remove;

       Especially for rearranging routes created by plugins this can be	very
       useful, to find routes by their name you	can use	"find" in
       Mojolicious::Routes::Route.

	 # GET /example/test ->	{controller => 'example', action => 'test'}
	 $r->get('/something/else')->to('something#else')->name('test');
	 my $test = $r->find('test');
	 $test->pattern->parse('/example/test');
	 $test->pattern->defaults({controller => 'example', action => 'test'});

       Even the	route pattern and destination can still	be changed with
       "parse" in Mojolicious::Routes::Pattern and "defaults" in
       Mojolicious::Routes::Pattern.

   Adding conditions
       You can also add	your own conditions with the method "add_condition" in
       Mojolicious::Routes. All	conditions are basically router	plugins	that
       run every time a	new request arrives, and which need to return a	true
       value for the route to match.

	 # A condition that randomly allows a route to match
	 $r->add_condition(random => sub ($route, $c, $captures, $num) {

	   # Loser
	   return undef	if int rand $num;

	   # Winner
	   return 1;
	 });

	 # /maybe (25% chance)
	 $r->get('/maybe')->requires(random => 4)->to('foo#bar');

       Use whatever request information	you need.

	 # A condition to check	query parameters (useful for mock web services)
	 $r->add_condition(query => sub	($route, $c, $captures,	$hash) {

	   for my $key (keys %$hash) {
	     my	$param = $c->req->url->query->param($key);
	     return undef unless defined $param	&& $param eq $hash->{$key};
	   }

	   return 1;
	 });

	 # /hello?to=world&test=1
	 $r->get('/hello')->requires(query => {test => 1, to =>	'world'})->to('foo#bar');

   Condition plugins
       You can also package your conditions as reusable	plugins.

	 # Plugin
	 package Mojolicious::Plugin::WerewolfCondition;
	 use Mojo::Base	'Mojolicious::Plugin', -signatures;

	 use Astro::MoonPhase;

	 sub register ($self, $app, $conf) {

	   # Add "werewolf" condition
	   $app->routes->add_condition(werewolf	=> sub ($route,	$c, $captures, $days) {

	     # Keep the	werewolves out!
	     return undef if abs(14 - (phase(time))[2])	> ($days / 2);

	     # It's ok,	no werewolf
	     return 1;
	   });
	 }

	 1;

       Now just	load the plugin	and you	are ready to use the condition in all
       your applications.

	 # Application
	 package MyApp;
	 use Mojo::Base	'Mojolicious', -signatures;

	 sub startup ($self) {

	   # Plugin
	   $self->plugin('WerewolfCondition');

	   # /hideout (keep them out for 4 days	after full moon)
	   $self->routes->get('/hideout')->requires(werewolf =>	4)->to(controller => 'foo', action => 'bar');
	 }

	 1;

   Mount applications
       The easiest way to embed	one application	into another is
       Mojolicious::Plugin::Mount, which allows	you to mount whole self-
       contained applications under a domain and/or prefix.

	 use Mojolicious::Lite -signatures;

	 # Whole application mounted under "/prefix"
	 plugin	Mount => {'/prefix' => '/home/sri/myapp/script/myapp'};

	 # Mount application with subdomain
	 plugin	Mount => {'test.example.com' =>	'/home/sri/myapp2.pl'};

	 # Normal route
	 get '/' => sub	($c) {
	   $c->render(text => 'Hello World!');
	 };

	 app->start;

   Embed applications
       For a little more power you can also embed applications by using	them
       instead of a controller.	This allows for	example, the use of the
       Mojolicious::Lite domain	specific language in normal Mojolicious
       controllers.

	 # Controller
	 package MyApp::Controller::Bar;
	 use Mojolicious::Lite -signatures;

	 # /hello
	 get '/hello' => sub ($c) {
	   my $name = $c->param('name');
	   $c->render(text => "Hello $name.");
	 };

	 1;

       With the	attribute "partial" in Mojolicious::Routes::Route, you can
       allow the route to partially match and use only the remaining path in
       the embedded application, the base path will be passed along in the
       "path" stash value.

	 # /foo/*
	 $r->any('/foo')->partial(1)->to('bar#', name => 'Mojo');

       A minimal embeddable application	is nothing more	than a subclass	of
       Mojolicious, containing a "handler" method accepting
       Mojolicious::Controller objects.

	 package MyApp::Controller::Bar;
	 use Mojo::Base	'Mojolicious', -signatures;

	 sub handler ($self, $c) {
	   $c->res->code(200);
	   my $name = $c->param('name');
	   $c->res->body("Hello	$name.");
	 }

	 1;

       The host	application will only share very little	information with the
       embedded	application through the	stash. So you cannot currently use
       route placeholders in routes leading to embedded	applications, since
       that would cause	problems with "url_for"	in Mojolicious::Controller.

   Application plugins
       You can even package applications as self-contained reusable plugins.

	 # Plugin
	 package Mojolicious::Plugin::MyEmbeddedApp;
	 use Mojo::Base	'Mojolicious::Plugin', -signatures;

	 sub register ($self, $app, $conf) {

	   # Automatically add route
	   $app->routes->any('/foo')->partial(1)->to(app => EmbeddedApp::app());
	 }

	 package EmbeddedApp;
	 use Mojolicious::Lite;

	 get '/bar' => 'bar';

	 1;
	 __DATA__
	 @@ bar.html.ep
	 Hello World!

       The "app" stash value, which won't be inherited by nested routes, can
       be used for already instantiated	applications.  Now just	load the
       plugin and you're done.

	 # Application
	 package MyApp;
	 use Mojo::Base	'Mojolicious', -signatures;

	 sub startup ($self) {

	   # Plugin
	   $self->plugin('MyEmbeddedApp');
	 }

	 1;

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

SUPPORT
       If you have any questions the documentation might not yet answer, don't
       hesitate	to ask in the Forum <https://forum.mojolicious.org> or the
       official	IRC channel "#mojo" on "irc.freenode.net" (chat	now!
       <https://webchat.freenode.net/#mojo>).

perl v5.32.1			  2020-12-27   Mojolicious::Guides::Routing(3)

NAME | OVERVIEW | CONCEPTS | BASICS | ADVANCED | MORE | SUPPORT

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=Mojolicious::Guides::Routing&sektion=3&manpath=FreeBSD+13.0-RELEASE+and+Ports>

home | help