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