[Catalyst-commits] r14412 - in trunk/examples/CatalystAdvent/root:
. 2012 2012/pen
skaufman at dev.catalyst.perl.org
skaufman at dev.catalyst.perl.org
Tue Dec 4 19:27:35 GMT 2012
Author: skaufman
Date: 2012-12-04 19:27:35 +0000 (Tue, 04 Dec 2012)
New Revision: 14412
Added:
trunk/examples/CatalystAdvent/root/2012/
trunk/examples/CatalystAdvent/root/2012/pen/
trunk/examples/CatalystAdvent/root/2012/pen/action_role_JSON.pod
Log:
First draft of action role JSON article
Added: trunk/examples/CatalystAdvent/root/2012/pen/action_role_JSON.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2012/pen/action_role_JSON.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2012/pen/action_role_JSON.pod 2012-12-04 19:27:35 UTC (rev 14412)
@@ -0,0 +1,129 @@
+
+=head1 Action Roles for cleaner less stashy Catalyst Actions
+
+=head2 Overview
+
+How to Serialize return values from Catalyst Actions
+
+=head3 About this Article
+
+Please note that this article leverages behavior that used to only exist in L<Catalyst::Controller::ActionRole>
+but has been merged into Catalyst proper in Catalyst v5.90013 .
+To take advantage of ActionRoles with an older Catalyst see the docs for L<Catalyst::Controller::ActionRole>.
+
+=head2 { hello => 'world' }
+
+
+Write a function that given a name, returns a user readable greeting along with a hashref of the data used.
+Simple.
+
+ sub hello {
+ my($name) = @_;
+ return {
+ message => "howdy $name",
+ metadata => {
+ name => $name,
+ },
+ };
+ }
+
+It's readable and extensible.
+Write a Catalyst action that does the same.
+
+ sub hello {
+ my ( $self, $ctx ) = @_;
+ my $name = $ctx->req->params->{name};
+ $ctx->res->headers->{ContentType} = "text/javascript";
+ $ctx->res->body(
+ $self->json->encode(
+ {
+ message => "hello $name!",
+ metadata => { name => $name },
+ }
+ )
+ );
+ }
+
+This is now pretty awful. A method that is supposed to take a string and transform it into a hashref is now:
+
+=over 2
+
+=item reading from the global "params"
+
+=item doing the transformation
+
+=item JSON encoding the response
+
+=back
+When that goes from being ugly to being a pain is when you decide you want to use L<Catalyst::Controller::REST>.
+
+The method becomes:
+
+ sub hello {
+ my ( $self, $ctx ) = @_;
+ my $name = $ctx->req->params->{name};
+ return $ctx->stash->{rest} =
+ {
+ message => "hello $name!",
+ metadata => { name => $name },
+ };
+ }
+
+And you now have to modify every action that used to use the first method.
+
+Let's clean this up a bit.
+
+In your controller:
+
+ __PACKAGE__->config(
+ action => {
+ hello => {
+ Does => "JSONEncode"
+ }
+ }
+ );
+
+....meanwhile, in lib/WebApp/ActionRole/JSONEncode.pm
+
+ package WebApp::ActionRole::JSONEncode;
+ use strictures 1;
+ use Moose::Role;
+ use JSON;
+ has json => (
+ is => 'ro',
+ default => sub { JSON->new }
+ );
+
+ around execute => sub {
+ # $self is the $c->action being 'executed'
+ my ( $orig, $self ) = ( shift, shift );
+ # execute is called on an action in a controller context
+ my ( $controller, $ctx ) = @_;
+ # wrap the original method
+ my $ret = $self->$orig(@_);
+ $ctx->res->headers->{ContentType} = "text/javascript";
+ $ctx->res->body( $self->json->encode( $ret ) );
+ return $ret;
+ };
+
+ no Moose::Role;
+ 1;
+
+The method now becomes:
+
+ sub hello {
+ my ( $self, $ctx ) = @_;
+ my $name = $ctx->req->params->{name};
+ return {
+ message => "hello $name!",
+ metadata => { name => $name },
+ };
+ )
+ }
+
+So while the 'name' param is still being grabbed from a global (we'll leave fixing that for another time and place), the method is returning the intended hash without worrying about the encoding.
+
+
+=head1 AUTHOR
+
+Samuel Kaufman <skaufman at cpan.org>
More information about the Catalyst-commits
mailing list