Search code examples
perldependency-injectiondancer2

In Dancer2, what is the preferred way to keep an instance of a service-like object, that a module's routes methods can access?


Imagine something along the lines of:

get( => 'hello' => sub ($app) {
    my $hello_service = $app->get_instance_of('hello_service');
    my $message = $hello_service->greet('world');
    template 'hello', {message => $message};
});

hello_service it a bit complex to initialize, I would not want to have to new it up on every request. I also don't want it to store it in package variable. Is there something in Dancer2 or some other trick that could allow me injecting services like that?


Solution

  • I like to initialize my service style classes with Bread::Board then expose them globally through a namespace like MyApp::Service, something like:

    package MyApp::Service;
    
    use Bread::Board;
    
    # Generate service depdencencies with Bread::Board
    my $c = container 'MyApp' => as {
        container 'Service' => as {
            service 'hello_service' => (
                lifecycle => 'Singleton',
                block     => sub {
                    require MyApp::Service::HelloService;
                    my $s = shift; # Use $s to resolve dependencies
                    return MyApp::Service::HelloService->new; # Do args and stuff here
                }
            );
        };
    };
    
    no Bread::Board;
    
    # Retrieve via MyApp::Service::hello_service
    sub hello_service { return $c->resolve('Service/hello_service') }
    

    There may be another way to do this, but this is the way I've always done it for Mojolicious, Dancer, etc. I know you mentioned not wanting to do it in a package variable (sorry).