NAME
Router::Generic - A general-purpose router for the web.
SYNOPSIS
Constructor
use Router::Generic;
my $router = Router::Generic->new();
Simple Route
$router->add_route(
name => 'Simple',
path => '/foo/bar',
target => '/foobar.asp',
);
$router->match('/foo/bar/'); # /foobar.asp
Simple Named Capture
$router->add_route(
name => 'Zipcodes',
path => '/zipcodes/:code',
target => '/zipcode.asp'
);
$router->match('/zipcodes/90210/'); # /zipcode.asp?code=90210
$router->match('/zipcodes/80104/'); # /zipcode.asp?code=80104
$router->match('/zipcodes/00405/'); # /zipcode.asp?code=00405
Another way to spell the same thing
$router->add_route(
name => 'Zipcodes',
path => '/zipcodes/{code}',
target => 'zipcode.asp'
);
Eager Named Capture
$router->add_route(
name => 'Eager',
path => '/stuff/{*Whatever}',
target => '/yay.asp',
);
$router->match('/stuff/blah/'); # /stuff/blah
$router->match('/stuff/a/b/c'); # /yay.asp?Whatever=a%2Fb%2Fc - (a/b/c escaped)
Named Capture with RegExp
$router->add_route(
name => 'ZipcodeRegexp',
path => '/zipcodesRegExp/{code:\d{5}}',
target => '/zipcode.asp'
);
$router->match('/zipcodesRegExp/90210/'); # /zipcode.asp?code=90210
$router->match('/zipcodesRegExp/80104/'); # /zipcode.asp?code=80104
$router->match('/zipcodesRegExp/00405/'); # /zipcode.asp?code=00405
More Interesting
$router->add_route(
name => 'WikiPage',
path => '/:lang/:locale/{*Article}',
target => '/wiki.asp',
defaults => {
Article => 'Home',
lang => 'en',
locale => 'us',
}
);
$router->match('/en/us/'); # /wiki.asp?lang=en&locale=us&Article=Home
$router->match('/fr/ca/'); # /wiki.asp?lang=fr&locale=ca&Article=Home
$router->match('/en/us/Megalomania'); # /wiki.asp?lang=en&locale=us&Article=Megalomania
Route with Default Values
$router->add_route({
name => 'IceCream',
path => '/ice-cream/:flavor',
target => '/dessert.asp',
defaults => {
flavor => 'chocolate'
}
});
Fairly Complex
$router->add_route(
name => "ProductReviews",
path => '/shop/{Product}/reviews/{reviewPage:\d+}',
target => '/product-reviews.asp',
defaults => {
reviewPage => 1,
}
);
$router->match('/shop/Ford-F-150/reviews/2/'); # /product-reviews.asp?Product=Ford-F-150&reviewPage=2
List of Targets
As of version 0.006 you can also pass an arrayref of targets and get them all back, parameterized just the same:
$router->add_route(
name => "Bank",
path => '/banks/:city',
target => [ '/bank-[:city:].asp', '/bank-generic.asp' ],
defaults => {
reviewPage => 1,
}
);
# Scalar context returns an arrayref when there are multiple targets:
my $matches = $router->match('/banks/Dallas/');
print $matches->[0]; # /bank-Dallas.asp?city=Dallas
print $matches->[1]; # /bank-generic.asp?city=Dallas
# List context returns a list:
my @matches = $router->match('/banks/Dallas/');
print $matches[0]; # /bank-Dallas.asp?city=Dallas
print $matches[1]; # /bank-generic.asp?city=Dallas
* This whole contextual-return-types thing started up in v0.007.
Get the URI for a Route
my $uri = $router->uri_for('IceCream');
print $uri; # /ice-cream/chocolate/
my $uri = $router->uri_for('/ProductReviews', {
Product => 'Tissot-T-Sport',
reviewPage => 3,
});
print $uri; # /shop/Tissot-T-Sport/reviews/3/
my $uri = $router->uri_for('WikiPage', {
Article => 'Self-aggrandizement',
lang => 'en',
locale => 'ca',
});
print $uri; # /en/ca/Self-aggrandizement/
my $uri = $router->uri_for('Zipcodes', {
code => '12345'
});
print $uri; # /zipcodes/12345/
Get the Route for a URI
my $route = $router->route_for('/banks/Dallas/');
my $route = $router->route_for('/banks/Dallas/', 'POST');
my $route = $router->route_for('/banks/Dallas/', 'GET');
DESCRIPTION
Router::Generic
provides URL Routing for the web.
What is URL Routing?
URL Routing is a way to connect the dots between a URL you see in your browser and the page that the webserver should actually process. You could also say that URL Routing is a way to abstract the URL in the browser from the page that the webserver should actually process. It's all in your perspective.
URL Routing is valuable for search engine optimization (SEO) and for reducing work associated with moving files and folders around during the iterative process of building a website.
Anatomy of a Route
Every route must have a name
, a path
and a target
. The defaults
hashref is optional.
name (Required)
The
name
parameter should be something friendly that you can remember and reference later.Examples are "Homepage" or "Products" or "SearchResults" - you get the picture.
path (Required)
The
path
parameter describes what the incoming URL will look like in the browser.Examples are:
/hello/:who
-
Matches
/hello/world/
and/hello/kitty/
Does not match
/hello/every/one/
/colors/{Color}
-
Matches
/colors/red/
and/colors/not-really-a-color/
Does not match
/colors/red/white/blue/
/options/{*Options}
-
Matches
/options/
,/options/foo/
and/options/foo/bar/baz/bux/
/areacodes/{Area:\d{3}}
-
You can use regular expressions to restrict what your paths match.
Matches
/areacodes/303/
but does not match/areacodes/abc/
target (Required)
The url that should be processed instead. Any string is accepted as valid input.
So
/ice-cream.asp
and/flavor.asp?yay=hooray
are OK.defaults (Optional)
The
defaults
parameter is a hashref containing values to be used in place of missing values from the path.So if you have a path like
/pets/{*petName}
and yourdefaults
looks like this:$router->add_route( name => 'Pets', path => '/pets/{*petName}', target => '/pet.asp', defaults => { petName => 'Spot', } );
You get this:
$router->match('/pets/'); # /pet.asp?petName=Spot
And this:
$router->uri_for('Pets'); # /pets/Spot/
The
defaults
are overridden simply by supplying a value:$router->match('/pets/Fluffy/'); # /pet.asp?petName=Fluffy
And this:
$router->uri_for('Pets', {petName => 'Sparky'}); # /pets/Sparky/
Caching
Router::Generic
provides route caching - so the expensive work of connecting a uri to a route is only done once.
PUBLIC METHODS
add_route( name => $str, route => $str, [ defaults => \%hashref ] )
Adds the given "route" to the routing table. Routes must be unique - so you can't have 2 routes that both look like /foo/:bar
for example. An exception will be thrown if an attempt is made to add a route that already exists.
Returns true on success.
match( $uri )
Returns the 'routed' uri with the intersection of parameters from $uri
and the defaults (if any).
Returns undef
if no matching route is found.
uri_for( $routeName, \%params )
Returns the uri for a given route with the provided params.
Given this route:
$router->add_route({
name => 'IceCream',
path => '/ice-cream/:flavor',
target => '/dessert.asp',
defaults => {
flavor => 'chocolate'
}
});
You would get the following results depending on what params you supply:
my $uri = $router->uri_for('IceCream');
print $uri; # /ice-cream/chocolate/
my $uri = $router->uri_for('IceCream', {
flavor => 'strawberry',
});
print $uri; # /ice-cream/strawberry/
route_for( $path, [ $method ] )
Returns the route matching the path and method.
LIMITATIONS
Before version 0.009 there were some limitations in the grammar that prevented paths like /wiki/:lang-:locale/{*Page}
from picking up the :lang
and :locale
correctly. As of version 0.009 this works correctly.
SIMPLE CRUD EXAMPLE
$router->add_route(
name => 'CreatePage',
path => '/main/:type/create',
target => '/pages/[:type:].create.asp',
method => 'GET'
);
$router->add_route(
name => 'Create',
path => '/main/:type/create',
target => '/handlers/dev.[:type:].create',
method => 'POST'
);
$router->add_route(
name => 'View',
path => '/main/:type/{id:\d+}',
target => '/pages/[:type:].view.asp',
method => '*',
);
$router->add_route(
name => 'List',
path => '/main/:type/list/{page:\d+}',
target => '/pages/[:type:].list.asp',
method => '*',
defaults => { page => 1 }
);
$router->add_route(
name => 'Delete',
path => '/main/:type/delete/{id:\d+}',
target => '/handlers/dev.[:type:].delete',
method => 'POST'
);
This works great with ASP4.
ACKNOWLEDGEMENTS
Part of the path parsing logic was originally based on Router::Simple by Matsuno Tokuhiro http://search.cpan.org/~tokuhirom/ et al.
The path grammar is a copy of the route grammar used by ASP.Net 4.
AUTHOR
John Drago <jdrago_999@yahoo.com>
LICENSE
This software is Free software and may be used and redistributed under the same terms as any version of Perl itself.