The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

Name

Forward::Guides::Routes::Resources - Rails like resource routing for Plack web framework developers (Perl)

Description

Forward::Routes provides support for Rails like resource routing. The add_resources command generates a bunch of routes that can be used to dispatch to a controller's read, create, update and delete actions and to display CRUD related forms. Framework builders are responsible to load the respective controller classes and to execute the desired controller method. Forward::Routes just generates the routes and in case of a match, provides a match object with the needed controller and action parameters.

# Routes root object
my $routes = Forward::Routes->new;

# Add a resource
$routes->add_resources('cities');

# The following routes are generated:

HTTP     Path                 Controller  Action        Route name
request                       parameter   parameter
method          

GET      /cities/new          Cities      create_form   cities_create_form
GET      /cities/:id          Cities      show          cities_show
GET      /cities/:id/edit     Cities      update_form   cities_update_form
GET      /cities/:id/delete   Cities      delete_form   cities_delete_form
GET      /cities              Cities      index         cities_index
POST     /cities              Cities      create        cities_create
PUT      /cities/:id          Cities      update        cities_update
DELETE   /cities/:id          Cities      delete        cities_delete

Each generated route will usually dispatch to a specific method (see action parameter above) which is used to:

Action (method)       Used to

create_form           display a form to create a new item
show                  display an individual item
update_form           display a form to update an existing item
delete_form           display a form to confirm the deletion of an existing item
index                 list all items
create                create a new item
update                update an existing item
delete                delete an existing item

The internal code to generate a resource makes use of nested routes:

my $resource = $routes->add_route('cities');

# get => /cities
$resource->add_route
  ->via('get')
  ->to("Cities#index")
  ->name('cities_index');

# post => /cities
$resource->add_route
  ->via('post')
  ->to("Cities#create")
  ->name('cities_create');

# get => /cities/new
$resource->add_route('/new')
  ->via('get')
  ->to("Cities#create_form")
  ->name('cities_create_form');

# nested route with id placeholder, placeholder can contain everything
# but dots and slashed (constraint)
my $nested = $resource->add_route(':id')
  ->constraints('id' => qr/[^.\/]+/);

# get => /cities/paris
$nested->add_route
  ->via('get')
  ->to("Cities#show")
  ->name('cities_show');

# put => /cities/paris
$nested->add_route
  ->via('put')
  ->to("Cities#update")
  ->name('cities_update');

# delete => /cities/paris
$nested->add_route
  ->via('delete')
  ->to("Cities#delete")
  ->name('cities_delete');

# get => /cities/paris/edit
$nested->add_route('edit')
  ->via('get')
  ->to("Cities#update_form")
  ->name('cities_update_form');

# get => /cities/paris/delete
$nested->add_route('delete')
  ->via('get')
  ->to("Cities#delete_form")
  ->name('cities_delete_form');

Multiple resources can be created with a single add_resources call:

# Add multiple resources
$routes->add_resources('cities', 'users', 'articles');

# equals
$routes->add_resources('cities'');
$routes->add_resources('users');
$routes->add_resources('articles');    

Resources inherit the file extension of their parent:

# in order to match get => /cities/paris/edit.html

# Routes root object
my $root = Forward::Routes->new;

# Create a parent route with format "html"
$route_with_html_extension = $root->add_route->format('html');

# add a resource on top of parent
$route_with_html_extension->add_resources('cities');

$m = $root->match(get => '/cities/paris/edit.html');
# $m->[0]->params is
#   {controller => 'Cities', action => 'cities_update_form',
#    format => 'html'};