What's in an appname?

New feature in Dancer2: appname

One change we absolutely love is the appname import option, introduced in Dancer2 0.150000.

What's a Dancer App again?

It's worth repeating the explanation of what a Dancer2 application is, since this might confuse a developer with a PSGI application.

A Dancer2 App is simply a package containing routes and engines which receives a request and returns a response. The engines are not mandatory, but might be a template, a session, a logger, and a serializer.

A PSGI application is a code reference which receives a request as a hash of environment variables (from a server using a Plack handler) and returns a proper PSGI response which could be an array reference or a code reference.

Too many apps!

As soon as you import Dancer2 (by calling use Dancer2), you create a Dancer2 App. It will use your class name (defined by either the package function in Perl or the default in Perl: main) to define the Dancer2 App name. This is how Dancer2 will recognize your application.

This introduces an interesting situation. If you wish to separate your App to multiple files, you're actually creating multiple applications.

So what?

This means that any engine defined in an application, because the application is a complete separate scope, will not be available to a different application:

package MyApp::User {
    use Dancer2;
    set serializer => 'JSON';
    get '/view' => sub {...};
}

package MyApp::User::Edit {
    use Dancer2;
    get '/edit' => sub {...};
}

These are two different Dancer2 Apps. They have different scopes, contexts, and thus different engines. While MyApp::User has a serializer (the JSON one) defined, MyApp::User::Edit will not have that configuration.

If you want the path /edit to have a serializer also, you will need to define one for MyApp::User::Edit. This is not just tedious, but when you mix this with the to_app method (described in the previous article, you have a problem:

use MyApp::User;
use MyApp::User::Edit;

use Plack::Builder;

builder {
    mount '/' => MyApp::User->to_app;
    # what about MyApp::User::Edit ???
};

If / is taken by MyApp::User, where do we put MyApp::User::Edit?

We don't actually wish MyApp::User::Edit to be another application, we just want it to be a comfortable extension to the regular app, providing additional routes that are part of the same already-existing application.

While you might think loading MyApp::User::Edit within MyApp::User will help to just extend it, that is not the case. It will still fail.

appname to the rescue!

appname saves the day

By using the import option appname, we can ask Dancer2 to extend an App without creating a new one:

package MyApp::User {
    use Dancer2;
    set serializer => 'JSON';
    get '/view' => sub {...};
}

package MyApp::User::Edit {
    use Dancer2 appname => 'MyApp::User'; # extending MyApp::User
    get '/edit' => sub {...};
}

Now, by using appname when importing, we can ask this App to simply extend an existing one (or one will be created if it does not exist yet) and add the routing there.

The serializer will be available, it will have the same configuration, and it will even represent all of the routes with the same internal application object.

# app.pl
use MyApp::User;
use MyApp::User::Edit;

# single application composed of routes provided in multiple files
MyApp::User->to_app;

Usually we would load classes that contain additional routes inside the original class they extend:

package MyApp::User {
    use Dancer2;
    use MyApp::User::Edit;
    set serializer => 'JSON';
    ...
}

This way we only need to load one when we create an app:

# app.pl:
use MyApp::User;
MyApp::User->to_app;

Conclusion

The import option appname allows you to seamlessly extend Dancer2 Apps without creating unnecessary additional applications or repeat any definitions.

This allows you to spread your application routes across multiple files and allow ease of mind when developing it, and accommodate multiple developers working on the same codebase.

Author

This article has been written by Sawyer X for the Perl Dancer Advent Calendar 2014.

Copyright

No copyright retained. Enjoy.

2014 // Sawyer X <xsawyerx@cpan.org>