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 $location = $p{'location'};
181 $c->response->status(201);
182 $c->response->header('Location' => $location);
183 $self->_set_entity($c, $p{'entity'});
187 =item status_accepted
189 Returns a "202 ACCEPTED" response. Takes an "entity" to serialize.
193 $self->status_accepted(
201 sub status_accepted {
210 $c->response->status(202);
211 $self->_set_entity($c, $p{'entity'});
215 =item status_bad_request
217 Returns a "400 BAD REQUEST" response. Takes a "message" argument
218 as a scalar, which will become the value of "error" in the serialized
223 $self->status_bad_request(
225 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(
254 message => "Cannot find what you were looking for!",
258 sub status_not_found {
263 message => { type => SCALAR },
267 $c->response->status(404);
268 $c->log->debug("Status Not Found: " . $p{'message'});
269 $self->_set_entity($c, { error => $p{'message'} });
277 if (defined($entity)) {
278 $c->stash->{$self->config->{'serialize'}->{'stash_key'}} = $entity;
285 =head1 MANUAL RESPONSES
287 If you want to construct your responses yourself, all you need to
288 do is put the object you want serialized in $c->stash->{'rest'}.
292 L<Catalyst::Action::REST>, L<Catalyst::Action::Serialize>,
293 L<Catalyst::Action::Deserialize>
295 For help with REST in general:
297 The HTTP 1.1 Spec is required reading. http://www.w3.org/Protocols/rfc2616/rfc2616.txt
299 Wikipedia! http://en.wikipedia.org/wiki/Representational_State_Transfer
301 The REST Wiki: http://rest.blueoxen.net/cgi-bin/wiki.pl?FrontPage
305 Adam Jacob <adam@stalecoffee.org>, with lots of help from mst and jrockway
307 Marchex, Inc. paid me while I developed this module. (http://www.marchex.com)
311 You may distribute this code under the same terms as Perl itself.