Announcing Mojolicious::Plugin::Routes::Restful

Have Hash Get Routes

One of my long standing mental code blocks has been trying to get me little brain to understand what a 'Route' is. This really came to a head when I first started to use Mojolicous in a big way.


You see in the old days it was easy, you just had an URL that pointed to something and you could either get or a post to it. It was of course used and abused in all sorts of ways, I still have a browser bookmark that looks like this Fragments Attachments/Lorica Hamata Armor Fragment/lorica hamata fragment.htm?counter=0111&pox=110103....

So the Web, in all its wisdom, came up with many ways to try to set some sort of standard for data transfer and that eventually morphed into what we all now call Web Services. Which to some looks more like this;


So over the years I have learned quite allot about building and designing content routes and web APIs. For example some of my early attempts look like this crap

foreach my $tab (qw( lab projects sites inventory chemicals admin hazmat )){
my $stash = {current_tab =>$tab,vtab=>$tab,current_vtab=>''};
$rn->route("/$tab") ->to("$tab#show", $stash);
$rn->route("/$tab/:action") ->to("$tab#show", $stash);
$rn->route("/$tab/:action/:id") ->to("$tab#show", $stash);
$rn->route("/$tab/:action/:id/:parent_id")->to("$tab#show", $stash);
foreach my $controller ((qw(experiment experiments notice order tasks type address project group groups detail profile institution plant site cabinet dimension
shelf bin container content chemical property user role time privilege ))){
my $stash = {current_tab =>$tab,vtab=>$tab,current_vtab=>$controller};
$rn->route("/$controller/:action/:id/:parent_id")->to("$controller#show", $stash);
$rn->route("/$controller/:action/:id") ->to("$controller#show", $stash);
$rn->route("/$controller/:action") ->to("$controller#show", $stash);
foreach my $sub_controller ((qw(view detail types data flow ))){
$rn->route("$tab/:action/:id/$controller/:action/$sub_controller/:id/:parent_id/:sub_parent_id")->to("$sub_controller#show", $stash);

Not easy to read and not easy to maintain!

One of the most important learning experiences was a RESTful API disaster I reported on. Specifically the code for all the RESTFul routes code looked something like this.

$r->get('/:pr/:p_id/:rs/:id')->to(controller => 'api', action => 'get');
$r->post('/:pr/:p_id/:rs/:id')->to(controller => 'api', action => 'post');
$r->put('/:pr/:p_id/:rs/:id')->to(controller => 'api', action => 'put');
$r->delete('/:pr/:p_id/:rs/:id')->to(controller => 'api', action => 'delete');

A little too open IMHO.

So I was motivated in my personal projects to improve on what I was doing and determined not make the sort of mistake like the above.

After a few projects I came up with design pattern that worked for me. A simple parent~child relationship where I defined my content routes and API routes at the same time.

Eventually the code evolved into a very stable state which I am now releasing to the world as Routes::Restful.

In brief you get

  • Configuration via a hash
  • Open only the RESTful resources you choose
  • A proven set of config attributes
  • A Limited RESTful API
  • No extra methods

Config Hash

A common set of well defined, and documented config attributes that give you 97.674% of route and API coverage you may need. It is just a hash, so you can load it via a YAML or any other file. Full words used for the attributes rather than single letters or abbreviations or control strings.

Control your RESTFul API

Only open the API routes you want. Have no use for PUT or PATCH then do not add them in.

Simple Attributes

I have been using this pattern for about 5 years and have come across almost every situation you may run into for routes and included it in the attributes. If you need to do something more complex the plugin returns the Mojo routes object so you play with that.

Limited the RESTFul API

With this plugin you can not define a DELETE or PUT route to a collection resource.


my $url = 'http://api/projects';
my $req = HTTP::Request->new(DELETE => $url);


my $url = 'http://api/projects/22/users/';
my $req = HTTP::Request->new(DELETE => $url);

will give you a 404. Unless you add this route yourself.

Nothing Extra
Sometimes on large project with a number of plug-ins sometimes it is nice to use something that does not open something else to keep track of.

So have a look and enjoy.


DELETE or PUT route to a collection resource […] will give you a 404.

Should be 405

Wonderful documentation!


Thanks for releasing this as it has saved me having to do it by hand on several projects.

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations