Strip trailing whitespace, tidy up and fix POD
[catagits/Catalyst-Action-REST.git] / lib / Catalyst / Action / REST.pm
CommitLineData
256c894f 1#
2# REST.pm
be3c588a 3# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
256c894f 4# Created on: 10/12/2006 03:00:32 PM PDT
5#
6# $Id$
7
8package Catalyst::Action::REST;
9
10use strict;
11use warnings;
12
13use base 'Catalyst::Action';
7ad87df9 14use Class::Inspector;
d4611771 15use Catalyst;
9a76221e 16use Catalyst::Request::REST;
ebba5325 17use Catalyst::Controller::REST;
18
9c5c9bd1 19BEGIN { require 5.008001; }
256c894f 20
e74d969d 21our $VERSION = '0.73';
9a76221e 22
5132f5e4 23sub new {
24 my $class = shift;
25 my $config = shift;
37694e6c 26 Catalyst::Request::REST->_insert_self_into( $config->{class} );
5132f5e4 27 return $class->SUPER::new($config, @_);
28}
7328f0ab 29
30=head1 NAME
31
32Catalyst::Action::REST - Automated REST Method Dispatching
33
34=head1 SYNOPSIS
35
5e87ec47 36 sub foo :Local :ActionClass('REST') {
37 ... do setup for HTTP method specific handlers ...
38 }
7328f0ab 39
afa581cf 40 sub foo_GET {
7328f0ab 41 ... do something for GET requests ...
42 }
43
afa581cf 44 sub foo_PUT {
7328f0ab 45 ... do somethign for PUT requests ...
46 }
47
48=head1 DESCRIPTION
49
50This Action handles doing automatic method dispatching for REST requests. It
51takes a normal Catalyst action, and changes the dispatch to append an
afa581cf 52underscore and method name.
7328f0ab 53
54For example, in the synopsis above, calling GET on "/foo" would result in
55the foo_GET method being dispatched.
56
afa581cf 57If a method is requested that is not implemented, this action will
58return a status 405 (Method Not Found). It will populate the "Allow" header
5e87ec47 59with the list of implemented request methods. You can override this behavior
60by implementing a custom 405 handler like so:
61
62 sub foo_not_implemented {
63 ... handle not implemented methods ...
64 }
65
66If you do not provide an _OPTIONS subroutine, we will automatically respond
67with a 200 OK. The "Allow" header will be populated with the list of
68implemented request methods.
7328f0ab 69
5e87ec47 70It is likely that you really want to look at L<Catalyst::Controller::REST>,
71which brings this class together with automatic Serialization of requests
72and responses.
398c5a1b 73
9a76221e 74When you use this module, the request class will be changed to
75L<Catalyst::Request::REST>.
76
7328f0ab 77=head1 METHODS
78
79=over 4
80
81=item dispatch
82
83This method overrides the default dispatch mechanism to the re-dispatching
84mechanism described above.
85
86=cut
d34c067a 87
256c894f 88sub dispatch {
bb4130f6 89 my $self = shift;
d34c067a 90 my $c = shift;
256c894f 91
2f91bf68 92 my $controller = $c->component( $self->class );
3faede66 93 my $rest_method = $self->name . "_" . uc( $c->request->method );
679978b1 94
3faede66 95 my ($code, $name);
679978b1 96
3faede66 97 # Common case, for foo_GET etc
98 if ($code = $controller->can($rest_method)) {
99 # Exceute normal action
100 $c->execute( $self->class, $self, @{ $c->req->args } );
101 $name = $rest_method;
256c894f 102 }
3faede66 103
104 # Generic handling for foo_OPTIONS
105 if (!$code && $c->request->method eq "OPTIONS") {
106 $name = $rest_method;
107 $code = sub { $self->_return_options($self->name, @_) };
108 }
109
110 # Otherwise, not implemented.
111 if (!$code) {
112 $name = $self->name . "_not_implemented";
113 $code = $controller->can($name) # User method
114 # Generic not implemented
115 || sub { $self->_return_not_implemented($self->name, @_) };
679978b1 116 }
256c894f 117
3faede66 118 # localise stuff so we can dispatch the action 'as normal, but get
119 # different stats shown, and different code run.
120 local $self->{code} = $code;
121 local $self->{reverse} = $name;
d34c067a 122
679978b1 123 $c->execute( $self->class, $self, @{ $c->req->args } );
d34c067a 124}
125
d2d93101 126sub _get_allowed_methods {
127 my ( $self, $controller, $c, $name ) = @_;
679978b1 128 my $class = ref($controller) ? ref($controller) : $controller;
129 my $methods = Class::Inspector->methods($class);
7ad87df9 130 my @allowed;
eccb2137 131 foreach my $method ( @{$methods} ) {
eccb2137 132 if ( $method =~ /^$name\_(.+)$/ ) {
133 push( @allowed, $1 );
7ad87df9 134 }
135 }
d34c067a 136 return @allowed;
679978b1 137};
138
139sub _return_options {
3faede66 140 my ( $self, $method_name, $controller, $c) = @_;
d2d93101 141 my @allowed = $self->_get_allowed_methods($controller, $c, $method_name);
679978b1 142 $c->response->content_type('text/plain');
143 $c->response->status(200);
144 $c->response->header( 'Allow' => \@allowed );
d34c067a 145}
146
147sub _return_not_implemented {
3faede66 148 my ( $self, $method_name, $controller, $c ) = @_;
d34c067a 149
d2d93101 150 my @allowed = $self->_get_allowed_methods($controller, $c, $method_name);
7ad87df9 151 $c->response->content_type('text/plain');
152 $c->response->status(405);
eccb2137 153 $c->response->header( 'Allow' => \@allowed );
154 $c->response->body( "Method "
155 . $c->request->method
156 . " not implemented for "
679978b1 157 . $c->uri_for( $method_name ) );
7ad87df9 158}
159
256c894f 1601;
7328f0ab 161
162=back
163
164=head1 SEE ALSO
165
166You likely want to look at L<Catalyst::Controller::REST>, which implements
167a sensible set of defaults for a controller doing REST.
168
169L<Catalyst::Action::Serialize>, L<Catalyst::Action::Deserialize>
170
5d7480da 171=head1 TROUBLESHOOTING
172
173=over 4
174
175=item Q: I'm getting a "415 Unsupported Media Type" error. What gives?!
176
69ad525b 177A: Most likely, you haven't set Content-type equal to "application/json", or
178one of the accepted return formats. You can do this by setting it in your query
179accepted return formats. You can do this by setting it in your query string
180thusly: C<< ?content-type=application%2Fjson (where %2F == / uri escaped). >>
5d7480da 181
69ad525b 182B<NOTE> Apache will refuse %2F unless configured otherise.
183Make sure C<< AllowEncodedSlashes On >> is in your httpd.conf file in orde
184for this to run smoothly.
5d7480da 185
69ad525b 186=back
5d7480da 187
2f7533ed 188=head1 MAINTAINER
7328f0ab 189
2f7533ed 190J. Shirley <jshirley@gmail.com>
7328f0ab 191
2f7533ed 192=head1 CONTRIBUTORS
398c5a1b 193
2f7533ed 194Christopher Laco
195
196Luke Saunders
197
198John Goulah
33e5de96 199
200Daisuke Maki <daisuke@endeworks.jp>
201
2f7533ed 202=head1 AUTHOR
203
204Adam Jacob <adam@stalecoffee.org>, with lots of help from mst and jrockway
205
206Marchex, Inc. paid me while I developed this module. (http://www.marchex.com)
207
7328f0ab 208=head1 LICENSE
209
210You may distribute this code under the same terms as Perl itself.
211
212=cut
d34c067a 213