Mojolicious Routes

This article assumes you are already aware of how to create the Mojolicious app.

The most basic Mojolicous routes accept a URI and providing a simple and expressive method of defining routes.

package App;
use Mojo::Base 'Mojolicious', -signatures;

# This method will run once at server start
sub startup ($self) {

  # Load configuration from config file
  my $config = $self->plugin('NotYAMLConfig');

  # Configure the application
  $self->secrets($config->{secrets});

  # Router
  my $r = $self->routes;

  # Normal route to controller
  $r->get('/')->to('Example#welcome');
}

1;

In general, all Mojolicous routes are in your [Your_App].pm files. This Perl package is in the lib directory. We can break this into another file, which we discuss later in the article. Mojolicious loads these routes during the start of the application. Most of the time, we define the routes in Your_App.pm file. We may access the URL by entering it in our browser.

In this example,

$r->get('/')->to('Example#welcome');

Example is the name of the Controller and welcome is the subroutine in it.

Available Routes Methods

We are allowed to register routes that respond to any HTTP queries:

  # Normal route to controller
  $r->get('/')->to('Example#welcome');

  # Post Method
  $r->post('/')->('Example#post_welcome');


  # Put Method
  $r->put('/')->('Example#put_welcome');

  # Any Method
  $r->any('/')->('Example#any_welcome');

  # Patch Method
  $r->patch('/')->('Example#path_welcome');

  # Remove method
  $r->find('/route_to_remove')->remove;
  
  # GET|POST Only                                            
  $r->any(['GET', 'POST'] => '/get_post_only')->to('Example#get_post_welcome');

Dynamic Routes

While developing the application, we need to know the parts of the URI within the route. For example, we may need to obtain a post id from the URL.

$r->get('/blog/:post_id')->to('Blog#post_view');

We can define as many route parameters or placeholders in the Mojolicious routes.

Conventional dynamic route parameters start with ":" and consist of alphabetic characters. Underscores (_) are also acceptable within route parameter names.

Placeholders in Dynamic Routes

Placeholders use a colon prefix and match all characters except / and ., similar to the regular expression.

$r->get('/user/:id')->to('User#user_details', id => '1');

In the above example, we are passing the value of id (1) to the controller.

We can also restrict the value of ids to be passed to the controller.

$r->get('/user/:id' => [id => ['1', '2']])->to('User#user_details');

Prefixing Route

Prefix a route or nested routes are not uncommon in web applications. For example, if a web application has an admin interface, all the URLs start with /admin word. It's not mandatory though good to follow this practice.

my $admin = $r->any('/admin')->to(controller => 'Admin', action -> 'default'); 
$admin->get('/login')->to(action -> 'login'); 
$admin->post('/login')->to(action -> 'login_post'); 
$admin->get('/dashboard')->to(action -> 'dashboard'); 

Protecting a Route

Sometimes, routes need to be protected like the user profile.

sub startup ($self) {
	# ........
	# Somewhere in the startup subroutine add 
	$self->_add_routes_authorization();

	# User Profile
	$r->get('/user/profile')->requires( user_authenticated => 1 )->to('User#show_profile');
    # .........
}

sub _add_routes_authorization {
	my $self = shift;

    $self->routes->add_condition(
    	user_authenticated => sub {
    	my ( $r, $c ) = @_;
    	return $c->redirect_to(
        	'/auth/signin?redirect=' . $c->req->headers->referrer
        );  
    # See Login using Mojolicious for this piece of code
    if ( !defined( $c->session('user_exists') ) ) ;

    	return 1;
    }
}

In the above case, if user_authenticated variable is not equal to 1 it'll redirect to signin page.

Prefixing Routes

Prefixing or Route groups allow you to share route attributes without redefining those attributes on each individual route. For example, you may want to prefix all route URIs within the group with the admin.

$r->add_shortcut(resource => sub ($r, $name) {

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

  # Admin Dashboard GET /admin/dashboard
  $resource->get('/dashboard')->to('#dashboard')->name($name);

  # /admin/user to list all users
  # GET /admin/user
  $resource->get('/user')->to('#user')->name("list_user");


  # show a specific user
  # GET /admin/user/:id
  $resource->get('/user/:id')->to('#show')->name("show_user");

  # Render a form to edit a user information
  # GET /admin/user/:id/edit
  $resource->get('/user/:id/edit')->to('#edit')->name("edit_user");

  # Store updated user information
  # POST /admin/user/:id
  $resource->put('/user/:id')->to('#update')->name("update_user");

  # Delete a resource
  # Delete /admin/user/:id
  $resource->delete('/user/:id')->to('#remove')->name("delete_user");

  return $resource;
});


$r->resource('admin');