Moving Perl Mojolicious routes to their own module
Tags: mojolicious, perl, webdev
Published: 2021-06-08 14:06:12

---
title: Moving Perl Mojolicious routes to their own module
published: true
date: 2021-06-08 14:00:00 UTC
tags: Mojolicious,Perl,webdev
canonical_url: https://phoenixtrap.com/2021/06/08/moving-perl-mojolicious-routes-to-their-own-module/?utm_source=rss&utm_medium=rss&utm_campaign=moving-perl-mojolicious-routes-to-their-own-module
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2hrzs4r3hyeepy4r02y.jpeg
---

A mentee asked me over the weekend if there was a way within a [Mojolicious](https://mojolicious.org/) web application to store the [routes](https://docs.mojolicious.org/Mojolicious/Guides/Routing) separately from the main application class. Here’s one way. **These instructions assume you’re using [Perl 5.34](https://www.perl.org/get.html) and [Mojolicious 9.19](https://metacpan.org/release/SRI/Mojolicious-9.19)** (the latest as of this writing) via the terminal command line on a Linux, Unix, or macOS system; make the appropriate changes if this doesn’t apply to you.

First, if you haven’t already, [create your Mojolicious app](https://docs.mojolicious.org/Mojolicious/Command/Author/generate/app) at your shell prompt:

```
$ mojo generate app Local::RouteDemo
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/script
  [write] /Users/mgardner/Projects/blog/local_route_demo/script/local_route_demo
  [chmod] /Users/mgardner/Projects/blog/local_route_demo/script/local_route_demo 744
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/lib/Local
  [write] /Users/mgardner/Projects/blog/local_route_demo/lib/Local/RouteDemo.pm
  [exist] /Users/mgardner/Projects/blog/local_route_demo
  [write] /Users/mgardner/Projects/blog/local_route_demo/local-route_demo.yml
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/lib/Local/RouteDemo/Controller
  [write] /Users/mgardner/Projects/blog/local_route_demo/lib/Local/RouteDemo/Controller/Example.pm
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/t
  [write] /Users/mgardner/Projects/blog/local_route_demo/t/basic.t
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/public
  [write] /Users/mgardner/Projects/blog/local_route_demo/public/index.html
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/templates/layouts
  [write] /Users/mgardner/Projects/blog/local_route_demo/templates/layouts/default.html.ep
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/templates/example
  [write] /Users/mgardner/Projects/blog/local_route_demo/templates/example/welcome.html.ep
$ cd local_route_demo
```

Create a new Perl module in your editor for storing your routes. Here we’re using `Local::RouteDemo::Routes`:

```
$ touch lib/Local/RouteDemo/Routes.pm
$ $EDITOR lib/Local/RouteDemo/Routes.pm
```

Make the module with a function that will create the routes you want, given a [Mojolicious::Routes](https://docs.mojolicious.org/Mojolicious/Routes) object. Here we’re just bringing over the default route created when we created our app:

```perl
package Local::RouteDemo::Routes;
use strict;
use warnings qw(all -experimental::signatures);
use feature 'signatures';
use Exporter 'import';
our @EXPORT_OK = qw(make_routes);

sub make_routes ($router) {
    $router->get('/')->to('Example#welcome');
    # add more routes here

    return;
}

1;
```

Adjust the application class to load your new Routes module and call its [exported](https://perldoc.pl/Exporter) function:

```perl
package Local::RouteDemo;
use Mojo::Base 'Mojolicious', -signatures;
use Local::RouteDemo::Routes 'make_routes';

# 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});

    # Make routes
    make_routes($self->routes);

    return;
}

1;
```

Finally, run your tests and/or manually test your routes to be sure everything works OK:

```
$ prove -vlr t
t/basic.t .. [2021-06-07 12:21:55.36917] [58779] [debug] [elVGykGVWlOt] GET "/"
[2021-06-07 12:21:55.36972] [58779] [debug] [elVGykGVWlOt] Routing to controller "Local::RouteDemo::Controller::Example" and action "welcome"
[2021-06-07 12:21:55.37137] [58779] [debug] [elVGykGVWlOt] Rendering template "example/welcome.html.ep"
[2021-06-07 12:21:55.37343] [58779] [debug] [elVGykGVWlOt] Rendering template "layouts/default.html.ep"
[2021-06-07 12:21:55.37495] [58779] [debug] [elVGykGVWlOt] 200 OK (0.005772s, 173.250/s)

ok 1 - GET /
ok 2 - 200 OK
ok 3 - content is similar
1..3
ok
All tests successful.
Files=1, Tests=3, 1 wallclock secs ( 0.02 usr 0.01 sys + 0.38 cusr 0.11 csys = 0.52 CPU)
Result: PASS
$ script/local_route_demo get /
[2021-06-07 12:22:29.55930] [58889] [debug] [f3YoaFhkwJ42] GET "/"
[2021-06-07 12:22:29.55990] [58889] [debug] [f3YoaFhkwJ42] Routing to controller "Local::RouteDemo::Controller::Example" and action "welcome"
[2021-06-07 12:22:29.56059] [58889] [debug] [f3YoaFhkwJ42] Rendering template "example/welcome.html.ep"
[2021-06-07 12:22:29.56269] [58889] [debug] [f3YoaFhkwJ42] Rendering template "layouts/default.html.ep"
[2021-06-07 12:22:29.56432] [58889] [debug] [f3YoaFhkwJ42] 200 OK (0.005004s, 199.840/s)
<!DOCTYPE html>
<html>
  <head><title>Welcome</title></head>
  <body><h2>Welcome to the Mojolicious real-time web framework!</h2>
<p>
  This page was generated from the template "templates/example/welcome.html.ep"
  and the layout "templates/layouts/default.html.ep",
  <a href="/">click here</a> to reload the page or
  <a href="/index.html">here</a> to move forward to a static page.
</p>
</body>
</html>
```

You can find [a git repository of this work on GitHub](https://github.com/mjgardner/local_route_demo), and here’s a [commit of all the changes made to the default Mojolicious application](https://github.com/mjgardner/local_route_demo/commit/ea1226793ae689ce7e049b36caaebccabb581c57) so you can see the differences.

## Update

[Joel Berg­er](https://jberger.github.io/) from the Mojo­li­cious project told me at [The Perl and Raku Con­fer­ence](https://perlconference.us/tprc-2021-cloud/) that it would be more idiomat­ic to use a [Mojo­li­cious plu­g­in](https://docs.mojolicious.org/Mojolicious/Guides/Routing#Application-plugins) rather than a plain mod­ule with an export, so here you go:

[lib/Local/RouteDemo.pm](https://github.com/mjgardner/local_route_demo/blob/master/lib/Local/RouteDemo.pm):

```perl
package Local::RouteDemo;
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});

    # Add routes from plugin
    $self->plugin('Local::RouteDemo::Plugin::Routes');

    return;
}

1;
```

[lib/Local/RouteDemo/Plugin/Routes.pm](https://github.com/mjgardner/local_route_demo/blob/master/lib/Local/RouteDemo/Plugin/Routes.pm):

```perl
package Local::RouteDemo::Plugin::Routes;
use Mojo::Base 'Mojolicious::Plugin', -signatures;

sub register ($self, $app, $conf) {
    my $r = $app->routes;

    $r->get('/')->to('Example#welcome');
    # add more routes here

    return;
}

1;
```