<< back

Dancer2::Controllers and Perl Attributes

Published February 26th, 2024.

Recently I created Dancer2::Controllers, a simple Moose based approach for defining routes in Dancer2. I built this as an attempt to add Spring-Boot esq annotations to Dancer2.

The approach

Perl has a little know feature called "Attributes", which work as some extra arbitrary data appended to the various reftypes in Perl. When you append an Attribute, Perl looks for the MODIFY_<reftype>_ATTRIBUTES in the current namespace, and uses it to decide if that attribute is allowed, and lets you execute some arbitrary code as well. Perl attributes can also take "arguments". These "arguments" actually are just part of the Attribute, and you need to parse the entire Attribute to get the arguments.

Since Perl Attributes are the closest thing I could find to annotations, I decided a generic Route attribute would be nice. With a Perly looking argument pattern: Route(get => /foo), this feels a Perl version of Spring-Boot's @RequestMapping(value = "/foo", method = GET), which is exactly what I was looking for.

Speed Bumps

Dancer2 is built on-top of Moo, unfortunately I couldn't find a nice way to handle Attributes using Moo, and inheritance. So, I settled for adding Moose and the wonderfully helpful MooseX::MethodAttributes dist, which drastically simplified the work I needed to do.

In action

The following is an example of how to use Dancer2::Controllers

:
            
package My::Controller;

use Moose;

BEGIN { extends 'Dancer2::Controllers::Controller' }

sub home_page : Route(get => /home) {
    my $app = shift;
    my $user_name = $app->session('user');
    return "Welcome back $user_name!";
}

sub home_page : Route(post => /login) {
    my $app = shift;
    my $password = $app->body_parameters->get('password');
    return "Here is your password: $password";
}

1;

package main;

use Dancer2;
use Dancer2::Controllers;

controllers([ 'My::Controller' ]);

dance;
            
            

Thanks for reading :)