Session support for Dancer, 1.0 is near

I’m glad to write this blog entry: Dancer now supports sessions.

Before giving you all the crunchy details about the implementation of that feature, let’s see some working code:

    post '/login' => sub {
        my $user = authenticate_user(params);
        if (defined $user) {
            session user_id => $user->id;
            return "Welcome aboard!";
        }
        else {
          return "Login failed";
        }
    };

    get '/home' => sub {
        if (not session('user_id')) {
            pass;
        }
        "Home sweet home";
    };

As I’m pretty happy with the implementation I came up with, I’m going to describe how sessions are handled in Dancer, and how one can write his own session engine.

First, I’d like to share the little brainstorming I had when I was thinking about how to bring session support into Dancer. At first, I wanted to depend on CGI::Session, assuming that users who want to use sessions within their Dancer app will have to install this module as well.

But afterall, I realized that writing a session engine was not such a big deal: it’s basically a question of storing a session id on the client side and using that session id as a key, for retreiving a previously serialized object on the server side.
There’s nothing much more complicated there.

My first reaction was to look at Sinatra, in order to see how it solves that issue.

Well, the fact is that Sinatra doesn’t hanlde sessions at all, Rack does. That means that you can’t write a session-aware app with Sinatra without installing Rack. Too bad.

By the way, will PSGI/Plack do the same? I’m curious about that…

Anyways, I took a look at Rack then, and discovered its own implementation of session handling. It’s pretty clean I must say: there is an abstract session class, that represents a typical session engine and a couple of session engines, implementing that class for particular session storages.

At that point, I decided to drop CGI::Session out of my dependency bag and start writing some code. As I liked Rack’s implementation, I pretty much did the same:

  • Dancer::Session – The gateway between the Dancer API and the chosen session engine.
  • Dancer::Session::Abstract – The abstract class representing a session engine interface, any new session engine must inherits from it and implement a set of methods (create, retreive, destroy and flush).
  • Dancer::Session::YAML – a YAML-file-based session engine, pretty convinient for development purposes
  • Dancer::Session::Memcached – a Memcached-based session engine

Here is as an example, the whole content of the Memcached implementation (I’ve just removed the bunch of initialization and sanity checks that occurs in init() for more readability).

package Dancer::Session::Memcached;

use strict;
use warnings;
use base 'Dancer::Session::Abstract';
use Dancer::Config 'setting';
use Dancer::ModuleLoader;

# singleton for the Memcached hanlde
my $MEMCACHED = undef;

sub init {
    my ($class) = @_;
    die "Cache::Memcached is needed and is not installed"
        unless Dancer::ModuleLoader->load('Cache::Memcached');

    my $servers = setting("memcached_servers");
    # ... check settings and initialize $servers correctly
    $MEMCACHED = Cache::Memcached->new(servers => $servers);
}

sub create {
    my ($class) = @_;
    my $self = $class->new;
    $MEMCACHED->set($self->id => $self);
    return $self;
}

sub retreive($$) {
    my ($class, $id) = @_;
    return $MEMCACHED->get($id);
}

sub destroy {
    my ($self) = @_;
    $MEMCACHED->delete($self->id);
}

sub flush {
    my $self = shift;
    $MEMCACHED->set($self->id => $self);
    return $self;
}

As you can see, there is really few code, we find here only the interesting parts: how to store and retreive information with a memcached backend.

Now, a user can use sessions with a memcached backend thanks to the following configuration file:

    # $appdir/config.yml
    session: "memcached"
    memcached_servers: "127.0.0.1:11211"

All of this is already available on GitHub and will be shiped as soon as the cookies support is finished, but that’s another topic ;)

Get Adobe Flash playerPlugin by wpburn.com wordpress themes