Writing a new Dancer serializer backend
Writing serializers in Dancer is so easy you can read this standing on your head!
In this entry we'll be writing a new serializer for Dancer and upload it to CPAN! Feel free to add your own once you finish reading this. :)
How do serializers work?
Serializers basically do two things:
- Serialize a data structure
Take a data structure as a parameter and return serialized data.
- Deserialize serialized data
Take serialized data as a parameter and return structured data.
Deciding on the serialization format
Serializes are so easy to write, Dancer already includes a few, such as:
- JSON
Using JSON.
- XML
Using XML::Simple.
- YAML
Using YAML.
- Dumper
Using Data::Dumper.
- Mutable
A self-adjusting serializer that uses the content type and accept headers.
Since these are already taken (unless you want to change one implementation with another, such as YAML for YAML::Tiny), there's not much point to write them again.
And since the recommended serialization formats are already mentioned above, it's a good reason to look into more nether regions, such as... UU encoding!
Of course, UU encoding isn't a format in its own, just an encoding so it isn't
recursive and we need to encode an entire structure recursively. We'll cheat
around it but using Storable's nfreeze
and then encoding it.
(credit goes out to Apache::Session for the idea)
Module skeleton
This should be the simplest skeleton, including just the required modules:
package Dancer::Serializer::UUEncode; use strict; use warnings; use Carp; use Storable qw/ nfreeze thaw /; use base 'Dancer::Serializer::Abstract'; # ... 1;
First, notice that we're using Dancer::Serializer::Abstract as a base, that's because we already implemented the Dancer integration logic under that base class. It promises us less work and more present and future portability. It also makes our module object oriented.
Methods
There are a three subroutines we should implement.
- serialize
The subroutine that does the serialization process itself.
sub serialize { my ( $self, $entity ) = @_; return pack( 'u', nfreeze($entity) ); }
Yes, that's it!
- deserialize
The subroutine that does the deserialization process itself.
sub deserialize { my ( $self, $content ) = @_; my $data = thaw( unpack( 'u', $content ) ); defined $data or croak "Couldn't thaw unpacked content '$content'"; return $data; }
- content_type
This subroutine simply returns the content type of our serialization. This is good practice for web applications so we'll implement it. If we don't, it will default to text/plain, which is good too.
sub content_type {'text/uuencode'}
We pretty much finished the serializer.
Did we really finish it so quickly?
Yes, we did!
What else can we do?
helpers
You can add helpers that will make it easier to use the serialize/deserialize
subroutines functionally outside of automatic serialization.
# helpers sub from_uuencode { my ($uuencode) = @_; my $s = Dancer::Serializer::UUEncode->new; return $s->deserializer($uuencode); } sub to_uuencode { my ($data) = @_; my $s = Dancer::Serializer::UUEncode->new; return $s->serialize($data); }
initializer
The init
subroutine is run on initialize of our object, and helps you take
care of initialize checks you might have.
sub init { # do some checks }
loader
The loaded
subroutine is not run by Dancer itself but it is common
practice to separate your lazy module loading to this subroutine and then run it
using the initializer.
If we would want to lazy load Storable, we could use these subroutines as such:
sub loaded { require Storable; Storable->import('nfreeze'); } sub init { my ($self) = @_; $self->loaded; }
CPAN, anyone?
While you've been reading this entry, I've taken the liberty to upload what we just wrote to CPAN and it should now be available as Dancer::Serializer::UUEncode. Nice, isn't it?
Feel free to send me your names so I could add you to the CREDITS section in the POD! :)
See also
- The previous article on Dancer Internals
- The following article on Writing a new Dancer logger backend
- The article after that on Writing a new Dancer session backend
Author
This article has been written by Sawyer X <xsawyerx@cpan.org>
for the
Perl Dancer Advent Calendar 2010.