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