1 package Catalyst::Controller::REST;
5 Catalyst::Controller::REST - A RESTful controller
9 package Foo::Controller::Bar;
11 use base 'Catalyst::Controller::REST';
13 sub thing : Local : ActionClass('REST') { }
15 # Answer GET requests to "thing"
17 my ( $self, $c ) = @_;
19 # Return a 200 OK, with the data in entity
20 # serialized in the body
25 foo => 'is real bar-y',
30 # Answer PUT requests to "thing"
37 Catalyst::Controller::REST implements a mechanism for building
38 RESTful services in Catalyst. It does this by extending the
39 normal Catalyst dispatch mechanism to allow for different
40 subroutines to be called based on the HTTP Method requested,
41 while also transparently handling all the serialization/deserialization for
44 This is probably best served by an example. In the above
45 controller, we have declared a Local Catalyst action on
46 "sub thing", and have used the ActionClass('REST').
48 Below, we have declared "thing_GET" and "thing_PUT". Any
49 GET requests to thing will be dispatched to "thing_GET",
50 while any PUT requests will be dispatched to "thing_PUT".
52 Any unimplemented HTTP METHODS will be met with a "405 Method Not Allowed"
53 response, automatically containing the proper list of available methods.
55 The HTTP POST, PUT, and OPTIONS methods will all automatically deserialize the
56 contents of $c->request->body based on the requests content-type header.
57 A list of understood serialization formats is below.
59 Also included in this class are several helper methods, which
60 will automatically handle setting up proper response objects
63 To make your Controller RESTful, simply have it
65 use base 'Catalyst::Controller::REST';
69 Catalyst::Controller::REST will automatically serialize your
70 responses. The currently implemented serialization formats are:
72 text/x-yaml -> YAML::Syck
73 text/x-data-dumper -> Data::Serializer
75 By default, L<Catalyst::Controller::REST> will use YAML as
76 the serialization format.
78 Implementing new Serialization formats is easy! Contributions
79 are most welcome! See L<Catalyst::Action::Serialize> and
80 L<Catalyst::Action::Deserialize> for more information.
84 These helpers try and conform to the HTTP 1.1 Specification. You can
85 refer to it at: http://www.w3.org/Protocols/rfc2616/rfc2616.txt.
86 These routines are all implemented as regular subroutines, and as
87 such require you pass the current context ($c) as the first argument.
95 use base 'Catalyst::Controller';
96 use Params::Validate qw(:all);
98 __PACKAGE__->mk_accessors(qw(serialize));
103 'stash_key' => 'rest',
105 'text/x-yaml' => 'YAML',
106 'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ],
112 sub begin : ActionClass('Deserialize') {}
114 sub end : ActionClass('Serialize') { }
118 Returns a "200 OK" response. Takes an "entity" to serialize.
125 radiohead => "Is a good band!",
140 $c->response->status(200);
141 $self->_set_entity($c, $p{'entity'});
147 Returns a "201 CREATED" response. Takes an "entity" to serialize,
148 and a "location" where the created object can be found.
152 $self->status_created(
154 location => $c->req->uri->as_string,
156 radiohead => "Is a good band!",
160 In the above example, we use the requested URI as our location.
161 This is probably what you want for most PUT requests.
170 location => { type => SCALAR | OBJECT },
171 entity => { optional => 1 },
176 if (ref($p{'location'})) {
177 $location = $p{'location'}->as_string;
179 $c->response->status(201);
180 $c->response->header('Location' => $location);
181 $self->_set_entity($c, $p{'entity'});
185 =item status_accepted
187 Returns a "202 ACCEPTED" response. Takes an "entity" to serialize.
191 $self->status_accepted(
199 sub status_accepted {
208 $c->response->status(202);
209 $self->_set_entity($c, $p{'entity'});
213 =item status_bad_request
215 Returns a "400 BAD REQUEST" response. Takes a "message" argument
216 as a scalar, which will become the value of "error" in the serialized
221 $self->status_bad_request(
224 message => "Cannot do what you have asked!",
229 sub status_bad_request {
234 message => { type => SCALAR },
238 $c->response->status(400);
239 $c->log->debug("Status Bad Request: " . $p{'message'});
240 $self->_set_entity($c, { error => $p{'message'} });
244 =item status_not_found
246 Returns a "404 NOT FOUND" response. Takes a "message" argument
247 as a scalar, which will become the value of "error" in the serialized
252 $self->status_not_found(
255 message => "Cannot find what you were looking for!",
260 sub status_not_found {
265 message => { type => SCALAR },
269 $c->response->status(404);
270 $c->log->debug("Status Not Found: " . $p{'message'});
271 $self->_set_entity($c, { error => $p{'message'} });
279 if (defined($entity)) {
280 $c->stash->{$self->config->{'serialize'}->{'stash_key'}} = $entity;
287 =head1 MANUAL RESPONSES
289 If you want to construct your responses yourself, all you need to
290 do is put the object you want serialized in $c->stash->{'rest'}.
294 L<Catalyst::Action::REST>, L<Catalyst::Action::Serialize>,
295 L<Catalyst::Action::Deserialize>
297 For help with REST in general:
299 The HTTP 1.1 Spec is required reading. http://www.w3.org/Protocols/rfc2616/rfc2616.txt
301 Wikipedia! http://en.wikipedia.org/wiki/Representational_State_Transfer
303 The REST Wiki: http://rest.blueoxen.net/cgi-bin/wiki.pl?FrontPage
307 Adam Jacob <adam@stalecoffee.org>, with lots of help from mst and jrockway
309 Marchex, Inc. paid me while I developed this module. (http://www.marchex.com)
313 You may distribute this code under the same terms as Perl itself.