--- /dev/null
+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;
+
--- /dev/null
+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;
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<deserialize> 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<serialize> 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<Catalyst::Controller::REST> will return a
--- /dev/null
+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;
'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 }
+ }
+ ],
},
);