why oh why does every class have VERSION???
[catagits/Catalyst-Action-REST.git] / lib / Catalyst / Action / Serialize.pm
CommitLineData
7ad87df9 1package Catalyst::Action::Serialize;
2
930013e6 3use Moose;
4use namespace::autoclean;
7ad87df9 5
930013e6 6extends 'Catalyst::Action::SerializeBase';
7ad87df9 7use Module::Pluggable::Object;
def65dcc 8use MRO::Compat;
7ad87df9 9
7566d72f 10our $VERSION = '1.13';
f465980c 11$VERSION = eval $VERSION;
12
0c14c8cd 13has _encoders => (
14 is => 'ro',
15 isa => 'HashRef',
16 default => sub { {} },
17);
18
7ad87df9 19sub execute {
20 my $self = shift;
21 my ( $controller, $c ) = @_;
22
def65dcc 23 $self->maybe::next::method(@_);
e601adda 24
7ad87df9 25 return 1 if $c->req->method eq 'HEAD';
786c212f 26 return 1 if $c->response->has_body;
7ad87df9 27 return 1 if scalar @{ $c->error };
bdff70a9 28 return 1 if $c->response->status =~ /^(?:204)$/;
02f66fc0 29 return 1 if defined $c->stash->{current_view};
30 return 1 if defined $c->stash->{current_view_instance};
7ad87df9 31
9a76221e 32 my ( $sclass, $sarg, $content_type ) =
33 $self->_load_content_plugins( "Catalyst::Action::Serialize",
34 $controller, $c );
51cc8fe9 35 unless ( defined($sclass) ) {
9a76221e 36 if ( defined($content_type) ) {
faf5c20b 37 $c->log->info("Could not find a serializer for $content_type");
9a76221e 38 } else {
faf5c20b 39 $c->log->info(
9cd203c9 40 "Could not find a serializer for an empty content-type");
9a76221e 41 }
51cc8fe9 42 return 1;
43 }
9a76221e 44 $c->log->debug(
faf5c20b 45 "Serializing with $sclass" . ( $sarg ? " [$sarg]" : '' ) ) if $c->debug;
7ad87df9 46
0c14c8cd 47 $self->_encoders->{$sclass} ||= $sclass->new;
48 my $sobj = $self->_encoders->{$sclass};
49
e601adda 50 my $rc;
878b2b54 51 eval {
52 if ( defined($sarg) ) {
0c14c8cd 53 $rc = $sobj->execute( $controller, $c, $sarg );
878b2b54 54 } else {
0c14c8cd 55 $rc = $sobj->execute( $controller, $c );
878b2b54 56 }
57 };
58 if ($@) {
b3996af8 59 return $self->serialize_bad_request( $c, $content_type, $@ );
878b2b54 60 } elsif (!$rc) {
b3996af8 61 return $self->unsupported_media_type( $c, $content_type );
9a76221e 62 }
7ad87df9 63
64 return 1;
eccb2137 65}
7ad87df9 66
05009b91 67__PACKAGE__->meta->make_immutable;
398c5a1b 68
d2c41c14 691;
70
398c5a1b 71=head1 NAME
72
73Catalyst::Action::Serialize - Serialize Data in a Response
74
75=head1 SYNOPSIS
76
77 package Foo::Controller::Bar;
78
79 __PACKAGE__->config(
faf5c20b 80 'default' => 'text/x-yaml',
81 'stash_key' => 'rest',
82 'map' => {
83 'text/html' => [ 'View', 'TT', ],
84 'text/x-yaml' => 'YAML',
85 'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ],
398c5a1b 86 }
87 );
88
e601adda 89 sub end :ActionClass('Serialize') {}
398c5a1b 90
91=head1 DESCRIPTION
92
93This action will serialize the body of an HTTP Response. The serializer is
e601adda 94selected by introspecting the HTTP Requests content-type header.
398c5a1b 95
faf5c20b 96It requires that your Catalyst controller is properly configured to set up the
97mapping between Content Type's and Serialization classes.
398c5a1b 98
faf5c20b 99The specifics of serializing each content-type is implemented as a plugin to
100L<Catalyst::Action::Serialize>.
398c5a1b 101
e601adda 102Typically, you would use this ActionClass on your C<end> method. However,
103nothing is stopping you from choosing specific methods to Serialize:
104
105 sub foo :Local :ActionClass('Serialize') {
106 .. populate stash with data ..
107 }
108
9a76221e 109When you use this module, the request class will be changed to
110L<Catalyst::Request::REST>.
111
398c5a1b 112=head1 CONFIGURATION
113
a51e7bbd 114=head2 map
398c5a1b 115
a51e7bbd 116Takes a hashref, mapping Content-Types to a given serializer plugin.
398c5a1b 117
a51e7bbd 118=head2 default
367b3ff4 119
a51e7bbd 120This is the 'fall-back' Content-Type if none of the requested or acceptable
121types is found in the L</map>. It must be an entry in the L</map>.
398c5a1b 122
0c14c8cd 123=head2 stash_key
398c5a1b 124
a51e7bbd 125Specifies the key of the stash entry holding the data that is to be serialized.
126So if the value is "rest", we will serialize the data under:
e601adda 127
128 $c->stash->{'rest'}
398c5a1b 129
a51e7bbd 130=head2 content_type_stash_key
398c5a1b 131
a51e7bbd 132Specifies the key of the stash entry that optionally holds an overriding
133Content-Type. If set, and if the specified stash entry has a valid value,
134then it takes priority over the requested content types.
398c5a1b 135
a51e7bbd 136This can be useful if you want to dynamically force a particular content type,
137perhaps for debugging.
398c5a1b 138
e601adda 139=head1 HELPFUL PEOPLE
140
141Daisuke Maki pointed out that early versions of this Action did not play
142well with others, or generally behave in a way that was very consistent
0c14c8cd 143with the rest of Catalyst.
e601adda 144
b3996af8 145=head1 CUSTOM ERRORS
146
147For building custom error responses when serialization fails, you can create
148an ActionRole (and use L<Catalyst::Controller::ActionRole> to apply it to the
149C<end> action) which overrides C<unsupported_media_type> and/or C<_serialize_bad_request>
150methods.
151
398c5a1b 152=head1 SEE ALSO
153
154You likely want to look at L<Catalyst::Controller::REST>, which implements
e601adda 155a sensible set of defaults for doing a REST controller.
398c5a1b 156
157L<Catalyst::Action::Deserialize>, L<Catalyst::Action::REST>
158
5cb5f6bb 159=head1 AUTHORS
398c5a1b 160
5cb5f6bb 161See L<Catalyst::Action::REST> for authors.
398c5a1b 162
163=head1 LICENSE
164
165You may distribute this code under the same terms as Perl itself.
166
167=cut