My second week of Dancer, now with queues and transactional email

Reading time: 7 minutes

A couple weeks ago, I wrote about my initial efforts with Dancer, Xslate and Bootstrap. Last week, I added the ability to send password reset emails. In the process, I’ve learned how to write Dancer plugins.

Designing a password reset system 🔗︎

Since I’ve never done it before, I decided to reinvent the wheel and make it work the way I think it should.

I broke the problem down into three big chunks:

  1. generate and store a random token
  2. send the token to a user’s registered email address
  3. receive the token and prompt a password change
Then I made a couple additional architectural decisions.
First, I decided to make the token system generic, as I expect there will be other things I'll use tokens for, such as email address confirmation. Regardless of the action that happens when the token is received, the first two steps above are nearly identical. All I need to do is make sure that tokens have a _type_ and can store whatever additional data is needed to complete the action.

Second, I decided to break email sending out of the web app itself. Instead, an email is generated within the app and dropped into an asynchronous message queue. A separate program monitors the queue and sends the emails. In addition to insulating the web app from latency from sending email, **a message queue makes unit testing a lot easier**. All I need to do is see if the web app dropped the right message into the queue. I don't have to mock up an email delivery system.

## Creating the token model

I decided it was sufficient to have a token be a URL-friendly, base64-encoded random value associated with a username, a "type" (e.g. password reset), an expiration, and an arbitrary "value" field.

For what it's worth, here's the trivial code for generating a random value:

<pre class="brush: perl; title: ; notranslate" title="">use MIME::Base64 qw/encode_base64url/;

use Data::Entropy::Algorithms qw/rand_bits/;

$token = encode_base64url( rand_bits(192) ),

One of the reasons for having a generic "value" field is that I'm using MongoDB for my data store, so any JSON-serializable data can go in there "for free". If I wasn't using a document-based data store, I'd have to think more carefully about the value field semantics, or I'd have to serialize to/from the field with JSON or <a href="http://p3rl.org/Sereal" title="Sereal" target="_blank">Sereal</a> or something like that.

Speaking of MongoDB, I've been pretty pleased with <a href="http://p3rl.org/Mongoose" title="Mongoose" target="_blank">Mongoose</a> as a MongoDB->Moose mapper and the related <a href="http://p3rl.org/Dancer::Plugin::Mongoose" title="Dancer::Plugin::Mongoose" target="_blank">Dancer::Plugin::Mongoose</a>. I can specify my model classes and their associated database connection parameters directly in the Dancer config.yml file. If I were using a relational database, I'd probably look into <a href="http://p3rl.org/Dancer::Plugin::DBIC" title="Dancer::Plugin::DBIC" target="_blank">Dancer::Plugin::DBIC</a>, instead.

## Loose coupling

Since I didn't want to send the email directly from the application, I needed a message queue. Since I'm using MongoDB and have other (backend) reasons for using it for other message queues, I decided to use it here as well. Otherwise, I might have explored Amazon SQS, Gearman, or Redis. Generally, my approach is to use a small number of versatile tools that I can develop expertise in rather than spread my expertise across a giant toolbox. This, of course, is why Perl is my #1 tool.

I had already written <a href="http://p3rl.org/MongoDBx::Queue" title="MongoDBx::Queue" target="_blank">MongoDBx::Queue</a>, so that was done. What I needed was to get Dancer to use it. A Dancer plugin for it would need to do a few useful things:

  1. Gather config data for (one or more) queues
  2. Instantiate a singleton for the life of the app
  3. Extend the Dancer DSL to provide access. </ol> 
    Again, I prefer loose coupling and frameworks, so instead of writing Dancer::Plugin::MongoDBx::Queue, instead I wrote <a href="http://p3rl.org/Dancer::Plugin::Queue" title="Dancer::Plugin::Queue" target="_blank">Dancer::Plugin::Queue</a>, which is a generic queue interface. Then I wrote <a href="http://p3rl.org/Dancer::Plugin::Queue::MongoDB" title="Dancer::Plugin::Queue::MongoDB" target="_blank">Dancer::Plugin::Queue::MongoDB</a> to implement the generic mechanism using MongoDBx::Queue.
    
    Other Dancers who might favor other message queue systems just need to write similar implementation plugins and then message queues become an interchangeable component, just like template systems and session management. Loose coupling for the win!
    
    Here is a slightly simplified version of the resulting code:
    
    <pre class="brush: perl; title: ; notranslate" title=""># generate reset token

my $token = schema(“token”)->new( user => $user->username, type => ‘p’, # password reset type ); $token->save;

queue the reset email 🔗︎

queue(“mx_out”)->add_msg( { to => $user->email, from => ‘support@example.com’, subject => ‘Did you forget your password?’, body => template( ‘emails/password_reset’, { username => $user->username, token_url => uri_for( ‘/confirm/’ . $token->token ), }, ), } );

    Once the reset email data goes into the queue, it waits for a separate worker process to retrieve the message and send it. At the moment, I'm using the <a href="http://postmarkapp.com/" title="Postmark" target="_blank">Postmark</a> email service to send my transactional emails. The worker is a pretty short Perl program that polls the message queue, retrieves new messages and hands them off via <a href="http://p3rl.org/WWW::Postmark" title="WWW::Postmark" target="_blank">WWW::Postmark</a>. 
    
    ## While I was at it...
    
    When working on Dancer::Plugin::Queue, I realized what I was doing was similar to a lot of other plugins I had examined. In the case of D::P::Queue, I had the added step of creating a role to define the generic interface, but leaving that aside, a lot of plugins are doing this:
    
      1. Loading a class
      2. Loading some config options
      3. Creating a singleton
    
    It's ridiculous to do that for any particular CPAN module you want to use within Dancer, so I wrote it generically as <a href="http://p3rl.org/Dancer::Plugin::Adapter" title="Dancer::Plugin::Adapter" target="_blank">Dancer::Plugin::Adapter</a>.
    
    If I weren't committed to using WWW::Postmark via a message queue, this is how I could use it directly within a Dancer app with Dancer::Plugin::Adapter:
    
    In the config.yml:
    
    <pre class="brush: plain; title: ; notranslate" title="">plugins:

Adapter: postmark: class: WWW::Postmark options: POSTMARK_API_TEST

    In the application:
    
    <pre class="brush: perl; title: ; notranslate" title="">use Dancer::Plugin::Adapter;

get ‘/send_email’ => sub { eval { service(“postmark”)->send( from => ‘me@domain.tld’, to => ‘you@domain.tld, them@domain.tld’, subject => ‘an email message’, body => “hi guys, what’s up?” ); }; return $@ ? “Error: $@” : “Mail sent”; };

    As long as the module needs only static data to initialize, Dancer::Plugin::Adapter does all the repetitive work. In my (not so) humble opinion, that makes a lot of useful CPAN modules trivial to use as singletons within Dancer. Enjoy!
    
    ## Pulling it together
    
    Once I could generate and send the reset email, I needed a handler to respond to someone clicking on the reset link. Most of the work was doing some rudimentary validation on the submitted token -- ensuring it was valid, not expired, and so on.
    
    I decided to treat a password reset token as a one-shot, password-equivalent-login and existing-password-revocation. I also track that the login happened via token, so that the password change form and logic can skip requiring the current password.
    
    Here is a simplified version of that code:
    
    <pre class="brush: perl; title: ; notranslate" title="">get '/confirm/:token' =&gt; sub {

unless ( params->{token} =~ /^[a-zA-Z0-9_=-]{32}$/ ) { return template ‘error’ => { error => “Invalid token” }; }

my $token = schema(“token”)->find_token( params->{token} ); if ( $token ) { $token->delete; # one-shot token, so delete from database } else { return template ‘error’ => { error => “Token not found” }; }

my $user = schema(“user”)->find_user( $token->user ); unless ($user) { return template ‘error’ => { error => “Token has invalid user” }; }

if ( time() > $token->expiration ) { return template ‘error’ => { error => “Token has expired” }; }

if ( $token->type eq ‘p’ ) { # password reset session user => $user->username; # treat as logged in session token => 1; # note they arrived via token $user->scramble_password; $user->save; redirect ‘/change_password’; } else { return template ‘error’ => { error => “Token not recognized” }; } };

    You can see how the token confirmation logic is nearly completely generic. I can add additional token types as needed, just with different logic for each.
    
    ## Summary
    
    After another week of work, the application continues to take shape. Here's what I got done:
    
      * Wrote and shipped a message queue plugin system and MongoDB implmentation
      * Wrote and shipped a generic CPAN module adapter plugin
      * Added a password reset feature that generates reset tokens and emails users
      * Added a password reset token handler
    
    It's still only the rough outline of an application, but Dancer feels less foreign and I'm about ready to get past basic user-account housekeeping and into the real feature set of the application.

•      â€¢      â€¢

If you enjoyed this or have feedback, please let me know by or