From: Brian Phillips Date: Wed, 12 Oct 2011 17:05:41 +0000 (-0500) Subject: allow request/response deserialization/serialization by callback X-Git-Tag: 1.08~66 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Action-Serialize-Data-Serializer.git;a=commitdiff_plain;h=178f8470708ff2ba9e1a761ceb3cd3c12ad9a778 allow request/response deserialization/serialization by callback --- diff --git a/lib/Catalyst/Action/Deserialize/Callback.pm b/lib/Catalyst/Action/Deserialize/Callback.pm new file mode 100644 index 0000000..fa421fe --- /dev/null +++ b/lib/Catalyst/Action/Deserialize/Callback.pm @@ -0,0 +1,47 @@ +package Catalyst::Action::Deserialize::Callback; + +use Moose; +use namespace::autoclean; +use Scalar::Util qw(openhandle); + +extends 'Catalyst::Action'; + +our $VERSION = '0.91'; +$VERSION = eval $VERSION; + +sub execute { + my $self = shift; + my ( $controller, $c, $callbacks ) = @_; + + my $rbody; + + # could be a string or a FH + if ( my $body = $c->request->body ) { + if(openhandle $body) { + seek($body, 0, 0); # in case something has already read from it + while ( defined( my $line = <$body> ) ) { + $rbody .= $line; + } + } else { + $rbody = $body; + } + } + + if ( $rbody ) { + my $rdata = eval { $callbacks->{deserialize}->( $rbody, $controller, $c ) }; + if ($@) { + return $@; + } + $c->request->data($rdata); + } else { + $c->log->debug( + 'I would have deserialized, but there was nothing in the body!') + if $c->debug; + } + return 1; +} + +__PACKAGE__->meta->make_immutable; + +1; + diff --git a/lib/Catalyst/Action/Serialize/Callback.pm b/lib/Catalyst/Action/Serialize/Callback.pm new file mode 100644 index 0000000..dba974a --- /dev/null +++ b/lib/Catalyst/Action/Serialize/Callback.pm @@ -0,0 +1,28 @@ +package Catalyst::Action::Serialize::Callback; + +use Moose; +use namespace::autoclean; + +extends 'Catalyst::Action'; +use YAML::Syck; + +our $VERSION = '0.91'; +$VERSION = eval $VERSION; + +sub execute { + my $self = shift; + my ( $controller, $c, $callbacks ) = @_; + + my $stash_key = ( + $controller->{'serialize'} ? + $controller->{'serialize'}->{'stash_key'} : + $controller->{'stash_key'} + ) || 'rest'; + my $output = $callbacks->{serialize}->( $c->stash->{$stash_key}, $controller, $c ); + $c->response->output( $output ); + return 1; +} + +__PACKAGE__->meta->make_immutable; + +1; diff --git a/lib/Catalyst/Controller/REST.pm b/lib/Catalyst/Controller/REST.pm index defe764..2499e83 100644 --- a/lib/Catalyst/Controller/REST.pm +++ b/lib/Catalyst/Controller/REST.pm @@ -234,6 +234,25 @@ Your views should have a C method like this: return $serialized; } +=item * Callback + +For infinite flexibility, you can provide a callback for the +deserialization/serialization steps. + + __PACKAGE__->config( + map => { + 'text/xml' => [ 'Callback', { deserialize => \&parse_xml, serialize => \&render_xml } ], + } + ); + +The C callback is passed a string that is the body of the +request and is expected to return a scalar value that results from +the deserialization. The C callback is passed the data +structure that needs to be serialized and must return a string suitable +for returning in the HTTP response. In addition to receiving the scalar +to act on, both callbacks are passed the controller object and the context +(i.e. C<$c>) as the second and third arguments. + =back By default, L will return a diff --git a/t/callback.t b/t/callback.t new file mode 100644 index 0000000..434289b --- /dev/null +++ b/t/callback.t @@ -0,0 +1,32 @@ +use strict; +use warnings; +use Test::More; +use FindBin; + +use lib ("$FindBin::Bin/lib", "$FindBin::Bin/../lib"); +use Test::Rest; + +use_ok 'Catalyst::Test', 'Test::Serialize'; + +my $t = Test::Rest->new('content_type' => 'text/my-csv'); + +my $has_serializer = eval "require XML::Simple"; + + my $monkey_template = { + monkey => 'likes chicken!', + }; + my $mres = request($t->get(url => '/monkey_get')); + ok( $mres->is_success, 'GET the monkey succeeded' ); + my $output = { split( /,/, $mres->content ) }; + is_deeply($output, $monkey_template, "GET returned the right data"); + + my $post_data = { + 'sushi' => 'is good for monkey', + }; + my $mres_post = request( $t->post( url => '/monkey_put', data => join( ',', %$post_data ) ) ); + ok( $mres_post->is_success, "POST to the monkey succeeded"); + is_deeply($mres_post->content, "is good for monkey", "POST data matches"); + +1; + +done_testing; diff --git a/t/lib/Test/Serialize/Controller/REST.pm b/t/lib/Test/Serialize/Controller/REST.pm index 5b7c4ec..fa1cac2 100644 --- a/t/lib/Test/Serialize/Controller/REST.pm +++ b/t/lib/Test/Serialize/Controller/REST.pm @@ -30,6 +30,12 @@ __PACKAGE__->config( 'text/javascript', => 'JSONP', 'application/x-javascript' => 'JSONP', 'application/javascript' => 'JSONP', + 'text/my-csv' => [ + 'Callback', { + deserialize => sub { return {split /,/, shift } }, + serialize => sub { my $d = shift; join ',', %$d } + } + ], }, );