[Catalyst-commits] r12404 - trunk/examples/CatalystAdvent/root/2009/pen

franck at dev.catalyst.perl.org franck at dev.catalyst.perl.org
Wed Dec 16 18:10:16 GMT 2009


Author: franck
Date: 2009-12-16 18:10:15 +0000 (Wed, 16 Dec 2009)
New Revision: 12404

Added:
   trunk/examples/CatalystAdvent/root/2009/pen/catalyst-action-rest.pod
Log:
writing rest api with catalyst

Added: trunk/examples/CatalystAdvent/root/2009/pen/catalyst-action-rest.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2009/pen/catalyst-action-rest.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2009/pen/catalyst-action-rest.pod	2009-12-16 18:10:15 UTC (rev 12404)
@@ -0,0 +1,172 @@
+=head1 Writing REST webservices with Catalyst::Action::REST
+
+=head2 What is REST
+
+REST means REpresentational State Transfer. The REST approach is to use the
+HTTP verbs (GET, PUT, POST, DELETE) to interact with a webservice; the content
+type of the request to determine the format of the response; and to map the
+URI to a resource. This can be represented by this simple query:
+
+    curl -X GET -H "Content-type: application/json" http://baseuri/book/1
+
+The query ask (GET) for the book (the ressource) with the id 1, and want the
+response (the content-type) in JSON.
+
+=head2 Using of Catalyst::Action::REST
+
+The Catalyst::Action::REST module is here to help us to easily create REST
+webserivce in Catalyst. 
+
+=head3 HTTP Verbs
+
+First you declare a new resource:
+
+    sub book : Local : ActionClass('REST') { }
+
+Then the subroutines for the method you want to handle for that resource:
+
+    sub book_GET {
+    }
+
+    sub book_POST {
+    }
+
+The first method will be executed each time you call the "book" resource,
+whatever the HTTP method is. Catalyst will now dispatch to the subroutine that
+have the appropriate name. So, when you call GET on the resource /book/, first
+it will go through the book subroutine, then the book_GET subroutine. If an id
+is always required to access the book resource (for GET and POST), you can put
+some code to check this in the book sub:
+
+    sub book : Local : ActionClass('REST') {
+        my ($self, $c, $id) = @_;
+        if (!$id) {
+            $self->status_bad_request($c, message => 'id is missing');
+            $c->detach();
+        }
+    }
+
+Then book_GET and book_POST subroutines will never be called if the argument id
+is missing.
+
+=head3 Serialization
+
+One of the best feature of this module, it's that it handle all the
+serialization/deserialization part for you. You don't need to know how the
+response have to be serialized before sending back to the client, or how the
+data sent to you were serilazed. 
+
+When a client make a request, Catalyst::Action::REST will try to find the
+appropriate content-type for this query from:
+
+=over 4
+
+=item B<content-type from the HTTP request>
+
+It tries to find in the HTTP header of the request the content-type. This
+value can be set like this:
+
+    my $req = HTTP::Request(GET => 'http://...');
+    $req->header('Content-Type' => 'application/json');
+
+=item B<content-type from the parameter>
+
+If the content-type is not found using the HTTP::Request, it will check the
+content-type parameter:
+
+    http://www.example.com/book/id?content-type=application/json
+
+This is nice, because you can do a request for a specific content type from
+your browser, without needing to change the content-type value from the
+header.
+
+=item B<Accept-Content from the HTTP::Request>
+
+Finaly, if nothing is found, it will extract the value from the Accept-Content
+from the HTTP request.
+
+=back
+
+=head3 HTTP Helpers
+
+Catalyst::Action::REST comes with many helper to generate the appropriate HTTP
+response to a query. When you receive a POST query, and you create a new entry
+from this, you can use the C<status_created> helper, that will generate an
+HTTP response with a code HTTP code 201. If a request got no record, you can
+use the C<status_bad_request> to return a 404.
+
+=head3 Configuration
+
+You can use Catalyst::Action::REST without doing any specific configuration.
+But you can easily customize most of it's parts. When you do
+C<$self->status_ok($c, entity => {foo => 'bar'})>, the content of entity will
+be set in the 'rest' key of the stash. You can change the name of this key:
+
+    __PACKAGE__->config('stash_key' => 'my_rest_key');
+
+By default, various serialisations are supported (JSON, YAML, but also
+storable, XML, ...). You may want to limit only some format for your
+application:
+
+    __PACKAGE__->config(map => {
+        'text/x-yaml' => 'YAML',
+        'application/json' => 'JSON',
+    });
+
+It's also possible to force a default serializer. If no serializer is found
+for a requested content-type, this is the one that will be used.
+
+    __PACKAGE__->config('default'   => 'application/json');
+
+=head2 Writing a simple controller
+
+You have a nice website with a database, and you want to provides to your user
+an easy way to access some data. 
+
+    package BookStore::Controller::API::REST;
+    use Moose;
+    BEGIN { extends 'Catalyst::Controller::REST' };
+
+    sub book : Local : ActionClass('REST') { }
+
+    sub book_get {
+        my ( $self, $c, $id ) = @_;
+        if ( !$id ) {
+            $self->status_bad_request( $c, message => "id is missing" );
+            $c->detach();
+        }
+
+        # do something clever
+        my $book = ... $self->status_ok( $c,
+            entity => { author => $book->author, title => $book->title } );
+    }
+
+    sub book_POST {
+        my ( $self, $c ) = @_;
+        my $book_content = $c->req->data;
+        # insert book
+        $self->status_created(
+            $c,
+            location => $c->req->uri->as_string,
+            entity   => { title => $book->title, author => $book->author }
+        );
+    }
+
+    sub book_PUT {
+        my ( $self, $c ) = @_;
+        my $new_quantity = $c->req->data->{quantity};
+        # update quantity
+    }
+
+    sub book_DELETE {
+        my ( $self, $c, $id ) = @_;
+        $self->status_accepted( $c, entity => { status => "deleted" } );
+    }
+
+    1;
+
+=head2 SEE ALSO
+
+L<http://www.catalystframework.org/calendar/2006/9>
+
+L<http://en.wikipedia.org/wiki/REST>
\ No newline at end of file




More information about the Catalyst-commits mailing list