package Dancer::Serializer::Mutable; use strict; use warnings; use base 'Dancer::Serializer::Abstract'; use Dancer::SharedData; my $serializer = { 'text/x-yaml' => 'YAML', 'text/html' => 'YAML', 'text/xml' => 'XML', 'text/x-json' => 'JSON', 'application/json' => 'JSON', }; my $loaded_serializer = {}; my $_content_type; sub _find_content_type { my ($self, $request) = @_; # first content type, second accept and final default my %content_types; my $params; if ($request) { $params = $request->params; } my $method = $request->method; if ($method =~ /^(?:POST|PUT)$/) { if ($request->{content_type}) { $content_types{$request->{content_type}} = 4; } if ($params && $params->{content_type}) { $content_types{$params->{content_type}} = 3; } } if ($request->{accept}) { $content_types{$request->{accept}} = 2; } if ($request->{'accept_type'}) { $content_types{$request->{accept_type}} = 1; } $content_types{'application/json'} = 0 unless defined $content_types{'application/json'}; return [ sort { $content_types{$b} <=> $content_types{$a} } keys %content_types ]; } sub serialize { my ($self, $entity) = @_; my $request = Dancer::SharedData->request; my $serializer = $self->_load_serializer($request); return $serializer->serialize($entity); } sub deserialize { my ($self, $content) = @_; my $request = Dancer::SharedData->request; my $serializer = $self->_load_serializer($request); return $serializer->deserialize($content); } sub content_type { my $self = shift; $_content_type; } sub support_content_type { my ($self, $ct) = @_; grep /^$ct$/, keys %$serializer; } sub _load_serializer { my ($self, $request) = @_; my $content_types = $self->_find_content_type($request); foreach my $ct (@$content_types) { if (exists $serializer->{$ct}) { my $module = "Dancer::Serializer::" . $serializer->{$ct}; if (!exists $loaded_serializer->{$module}) { if (Dancer::ModuleLoader->load($module)) { my $serializer_object = $module->new; $loaded_serializer->{$module} = $serializer_object; } } $_content_type = $ct; return $loaded_serializer->{$module}; } } } 1; __END__ =head1 NAME Dancer::Serializer::Mutable - (De)Serialize content using the appropriate HTTP header =head1 SYNOPSIS =head1 DESCRIPTION This serializer will try find the best (de)serializer for a given request. For this, it will go through: =over =item The B<content_type> from the request headers =item the B<content_type> parameter from the URL =item the B<accept> from the request headers =item The default is B<application/json> =back =head2 METHODS =head2 serialize Serialize a data structure. The format it is serialized to is determined automatically as described above. It can be one of YAML, XML, JSON, defaulting to JSON if there's no clear preference from the request. =head2 deserialize Deserialize the provided serialized data to a data structure. The type of serialization format depends on the request's content-type. For now, it can be one of YAML, XML, JSON. =head2 content_type Returns the content-type that was used during the last C<serialize> / C<deserialize> call. B<WARNING> : you must call C<serialize> / C<deserialize> before calling C<content_type>. Otherwise the return value will be C<undef>.