[Catalyst-commits] r7713 - in Catalyst-Controller-REST-DBIC-Item/trunk/0.01: lib/Catalyst/Controller/REST/DBIC lib/Catalyst/Helper/Controller/REST/DBIC t

jshirley at dev.catalyst.perl.org jshirley at dev.catalyst.perl.org
Wed May 7 18:15:03 BST 2008


Author: jshirley
Date: 2008-05-07 18:15:02 +0100 (Wed, 07 May 2008)
New Revision: 7713

Modified:
   Catalyst-Controller-REST-DBIC-Item/trunk/0.01/lib/Catalyst/Controller/REST/DBIC/Item.pm
   Catalyst-Controller-REST-DBIC-Item/trunk/0.01/lib/Catalyst/Helper/Controller/REST/DBIC/Item.pm
   Catalyst-Controller-REST-DBIC-Item/trunk/0.01/t/00-load.t
Log:
Better pod, renamed the rest base midpoints to have a rest_ prefix.

Modified: Catalyst-Controller-REST-DBIC-Item/trunk/0.01/lib/Catalyst/Controller/REST/DBIC/Item.pm
===================================================================
--- Catalyst-Controller-REST-DBIC-Item/trunk/0.01/lib/Catalyst/Controller/REST/DBIC/Item.pm	2008-05-07 15:19:27 UTC (rev 7712)
+++ Catalyst-Controller-REST-DBIC-Item/trunk/0.01/lib/Catalyst/Controller/REST/DBIC/Item.pm	2008-05-07 17:15:02 UTC (rev 7713)
@@ -9,7 +9,7 @@
 
 =head1 NAME
 
-Catalyst::Controller::REST::DBIC::Item - Common base class for typical REST
+Catalyst::Controller::REST::DBIC::Item - (EXPERIMENTAL) Common base class for typical REST
 actions against a DBIx::Class object
 
 =head1 VERSION
@@ -18,12 +18,13 @@
 
 =cut
 
-our $VERSION = '0.01';
+our $VERSION = '0.01001';
 
 =head1 DESCRIPTION
 
-This is a controller base class that is designed to build some conventions
-around integrating REST and DBIC together in a Catalyst application.
+This is an experimental controller base class that is designed to build some 
+conventions around integrating REST and DBIC together in a Catalyst 
+application.
 
 The idea of this class is that, in the simplest terms, each item in a REST
 application has one URL to interface with it.  Typically, these objects have a 
@@ -31,6 +32,18 @@
 the repetition in your REST classes and allow you to focus on just handling
 the individual verbs (GET, PUT, POST, etc)
 
+=head1 PHILOSOPHY
+
+The general ideas for this module are such that I don't expect it to be of the
+most use for a CRUD application designed to function in a browser.  Most
+modern browsers support all the REST verbs via XmlHttpRequest but standard
+requests are still limited to GET and POST.  This package will have the most
+influence in a webservice scenario, and I hope that adapter classes can be
+built upon this one that will combine L<Catalyst::Request::REST::ForBrowsers>
+and other utilities to create controllers that work equally well in a
+browser-based setting.
+
+
 =head1 SYNOPSIS
 
     package MyApp::Controller::Person;
@@ -42,19 +55,53 @@
         'default' => 'text/html'
         # And, our bindings to DBIC, will use 
         # $c->model('Schema::Person') effectively.
-        resultset => 'Schema:;Person',
-        # Optional configuration for templates
-        templates => {
-            not_found => 'errors/not_found.tt'
-        }
+        class => 'Schema::Person',
+        # To find a record, $c->model($class)->search( $item_key => $key )
+        item_key => 'name',
+        # If you want to call a method before sending it to the serializers
+        serialize_method => 'serialize',
+        # Set to 0 if you don't want to call the above serialize method 
+        # if the request is in a browser
+        browser_serialize => 0
     );
 
     # This operates off of chained, and requires rest_base to be defined
-    
     sub rest_base : Chained('.') PathPart('person') CaptureArgs(0) { }
 
-    1;
+=head1 Overriding Default Methods
 
+Catalyst::Controller::REST::DBIC::Item operates by using Chained, which allows
+for midpoints to be overridden easily as long as you maintain the conventions.
+
+If you want to override one of the default chained midpoints, you only have
+to be mindful of which stash key to set.  By default, the stash key:
+C<< $c->stash->{rest}->{item} >> is used for fetching a single item.  If you
+want to add additional DBIC logic, such as a prefetch, you can override
+the item_base midpoint and properly set the stash.  Here is an example from
+the L<http://www.iwatchsoccer.com> source (available at 
+L<http://our.coldhardcode.com/svn/IWS>, which prefetches games to reduce the 
+total number of queries.
+
+    sub item_base : Chained('rest_base') PathPart('') CaptureArgs(1) {
+        my ( $self, $c, $identifier ) = @_;
+
+        # just populate $c->stash->{rest}->{item} and item_GET, etc
+        $c->stash->{rest}->{item} = $self->get_item($c, $identifier)->search(
+            {
+                'games.end_time' => { '>=', $c->stash->{now} }
+            },
+            {
+                prefetch => {
+                    games => [
+                        'home', 'visitor',
+                        { broadcasts => 'network' }
+                    ]
+                }
+            }
+        )->single;
+    }
+
+
 =head1 CONFIGURATION
 
 =over
@@ -89,11 +136,23 @@
 
 =cut
 
-sub list : Chained('rest_base') PathPart('') Args(0) ActionClass('REST') {
+sub rest_list : Chained('rest_base') PathPart('') Args(0) ActionClass('REST') {
 
 }
 
-sub list_GET {
+=head2 rest_list_GET
+
+The simple method that handles GET actions on the list action (A call to 
+C</foo>).
+
+This method will call the C<serialize_method>, if configured, as well as respect
+the C<browser_serialize> configuration setting if the request looks like it
+is coming from a browser (which requires L<Catalyst::Request::REST::ForBrowsers>
+to be loaded).
+
+=cut
+
+sub rest_list_GET {
     my ( $self, $c ) = @_;
 
     my $rs = $self->get_rs($c);
@@ -114,24 +173,54 @@
 }
 
 
-=head2 rest_item PathPart('') CaptureArgs(1)
+=head2 rest_item_base : Chained('rest_base') PathPart('') CaptureArgs(1)
 
-This method is used to handle triggering the single item methods.  Override
-rest_item_GET, rest_item_POST, etc to have custom behavior.
+This chain midpoint fetches the record by the captured argument (which should
+be the record identifier).  
 
+Override this method if you want to customize how the record is fetched.  It
+is expected that if a record is found, C<< $c->stash->{rest}->{item} >> is set.
+If not, the default GET request will return not found.
+
 =cut
 
-sub item_base : Chained('rest_base') PathPart('') CaptureArgs(1) {
+sub rest_item_base : Chained('rest_base') PathPart('') CaptureArgs(1) {
     my ( $self, $c, $pk1 ) = @_;
 
-    $c->stash->{rest}->{item} = $self->get_item( $c, $pk1 )->first;
+    $c->stash->{rest}->{item} = $self->get_item( $c, $pk1 )->single;
 }
 
-sub item : Chained('item_base') PathPart('') Args(0) ActionClass('REST') {
+=head2 rest_item
+
+This method chains to rest_item_base, has 0 arguments and uses
+L<Catalyst::Action::REST>.
+
+This method is used to handle triggering the single item methods.  Override
+rest_item_GET, rest_item_POST, etc to have custom serialization behavior.
+
+If you want to override the item selection, override rest_item_base
+
+=cut
+
+sub rest_item : Chained('rest_item_base') PathPart('') Args(0) ActionClass('REST') {
     my ( $self, $c ) = @_;
 }
 
-sub item_GET {
+=head2 rest_item_GET
+
+The default method for handling a simple GET request.  This will serialize 
+however L<Catalyst::Controller::REST> is configured for the controller, and
+will call the C<serialize_method> if configured (while respecting the
+C<browser_serialize> configuration setting).
+
+If the item is not found (which means C<< $c->stash->{rest}->{item} >> is not
+defined) it will return a status_not_found result, with the message:
+            
+    message => $c->localize('ITEM_NOT_FOUND') );
+
+=cut
+
+sub rest_item_GET {
     my ( $self, $c ) = @_;
     my $item;
     unless ( $item = $c->stash->{rest}->{item} ) {
@@ -156,8 +245,13 @@
     return $self->status_ok( $c, entity => $entity );
 }
 
-=head1 get_item($c, $identifier)
+=head1 HELPER METHODS
 
+The following methods are convenience methods that can be used in your methods
+to fetch items out of DBIC.
+
+=head2 get_item($context, $identifier)
+
 This method should return a result set that points to a single item that is
 identified by $identifier.
 
@@ -183,8 +277,22 @@
     }
 }
 
+=head2 get_rs($context)
+
+This fetches the result set to be used.  This is a good point to override for
+adding things like pagination.  A simple example for overriding would be:
+
+ sub get_rs {
+    my $rs = shift->next::method(@_);
+    return $rs->search(undef, { rows => 10, page => 1 });
+ }
+
+Just make sure this always returns a result set.
+
+=cut
+
 sub get_rs {
-    my ( $self, $c, $item ) = @_;
+    my ( $self, $c ) = @_;
     my $model = $self->{class};
     my $rs    = $c->model($model);
     croak "Unable to find DBIC resultset $model, check config"

Modified: Catalyst-Controller-REST-DBIC-Item/trunk/0.01/lib/Catalyst/Helper/Controller/REST/DBIC/Item.pm
===================================================================
--- Catalyst-Controller-REST-DBIC-Item/trunk/0.01/lib/Catalyst/Helper/Controller/REST/DBIC/Item.pm	2008-05-07 15:19:27 UTC (rev 7712)
+++ Catalyst-Controller-REST-DBIC-Item/trunk/0.01/lib/Catalyst/Helper/Controller/REST/DBIC/Item.pm	2008-05-07 17:15:02 UTC (rev 7713)
@@ -14,10 +14,28 @@
 
 =head1 DESCRIPTION
 
-Helper to create REST Base classes.
+Helper to create REST Base classes.  After this, you should be reading up on
+L<Catalyst::Controller::REST::DBIC::Item>
 
+=head1 METHODS
+
+=head2 mk_compclass
+
+This generates the individual REST classes
+
+=cut
+
+sub mk_compclass {
+    my ( $self, $helper, $schema_class ) = @_;
+    $helper->{schema_class} = $helper;
+    my $file = $helper->{file};
+    $helper->render_file( 'compclass', $file );
+}
+
 =head1 SEE ALSO
 
+L<Catalyst::Controller::REST::DBIC::Item>
+
 L<Catalyst::Action::REST>
 
 L<Catalyst::Model::DBIC::Schema>
@@ -33,13 +51,8 @@
 
 =cut
 
-sub mk_compclass {
-    my ( $self, $helper, $schema_class ) = @_;
-    $helper->{schema_class} = $helper;
-    my $file = $helper->{file};
-    $helper->render_file( 'compclass', $file );
-}
 
+
 1;
 
 __DATA__

Modified: Catalyst-Controller-REST-DBIC-Item/trunk/0.01/t/00-load.t
===================================================================
--- Catalyst-Controller-REST-DBIC-Item/trunk/0.01/t/00-load.t	2008-05-07 15:19:27 UTC (rev 7712)
+++ Catalyst-Controller-REST-DBIC-Item/trunk/0.01/t/00-load.t	2008-05-07 17:15:02 UTC (rev 7713)
@@ -18,12 +18,12 @@
 
 # Create a book called 'name'
 my $res = $mech->get('/book/test_book', 'Content-type' => 'text/x-yaml' );
-diag( $res->content );
+
 is($res->code, '404', "Book doesn't exist");
 my $test_data = YAML::Syck::Dump({ name => "test_book", isbn => "1234" });
-diag( $test_data );
 
-my $res = $mech->post( '/book/test_book', 
+
+$res = $mech->post( '/book/test_book', 
     'Content-type' => 'text/x-yaml',
     Content => $test_data 
 );
@@ -31,7 +31,7 @@
 is($res->code, '405', "Book has no post method");
 like($res->content, qr/Method POST not implemented/, 'No post on book');
 
-my $res = $mech->put( '/book/test_book', 
+$res = $mech->put( '/book/test_book', 
     'Content-type' => 'text/x-yaml',
     Content => $test_data 
 );




More information about the Catalyst-commits mailing list