[Bps-public-commit] r11627 - in SVN-PropDB: . lib/Prophet t

jesse at bestpractical.com jesse at bestpractical.com
Mon Apr 7 14:38:36 EDT 2008


Author: jesse
Date: Mon Apr  7 14:38:35 2008
New Revision: 11627

Added:
   SVN-PropDB/lib/Prophet/Server/
   SVN-PropDB/lib/Prophet/Server/REST.pm
Modified:
   SVN-PropDB/   (props changed)
   SVN-PropDB/lib/Prophet/CLI.pm
   SVN-PropDB/t/resty-server.t

Log:
 r29453 at 31b:  jesse | 2008-04-07 13:18:43 -0400
 * initial version of a resty server for your prophet database


Modified: SVN-PropDB/lib/Prophet/CLI.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/CLI.pm	(original)
+++ SVN-PropDB/lib/Prophet/CLI.pm	Mon Apr  7 14:38:35 2008
@@ -290,6 +290,15 @@
 
 }
 
+sub do_server {
+    my $self = shift;
+
+    my $opts = $self->args();
+    require Prophet::Server::REST;
+    my $server = Prophet::Server::REST->new( $opts->{'port'} || 8080);
+    $server->prophet_handle($self->handle);
+    $server->run;
+}
 
 sub do_merge {
     my $self = shift;
@@ -338,4 +347,6 @@
     }
 
 
+
+
 1;

Added: SVN-PropDB/lib/Prophet/Server/REST.pm
==============================================================================
--- (empty file)
+++ SVN-PropDB/lib/Prophet/Server/REST.pm	Mon Apr  7 14:38:35 2008
@@ -0,0 +1,142 @@
+use warnings;
+use strict;
+
+package Prophet::Server::REST;
+use base qw/HTTP::Server::Simple::CGI/;
+use Params::Validate qw/:all/;
+use JSON;
+
+sub prophet_handle {
+    my $self = shift;
+    $self->{'_prophet_handle'} = shift if (@_);
+    return $self->{'_prophet_handle'};
+}
+
+
+
+sub handle_request {
+    my $self = shift;
+    my ($cgi) = validate_pos(@_, { isa=> 'CGI'});
+    my $http_status; 
+    if (my $sub = $self->can('handle_request_'.lc($cgi->request_method))) {
+        $http_status  =  $sub->($self, $cgi);
+    } 
+    unless ($http_status) {
+        $self->_send_404;
+    }
+}
+
+sub handle_request_get {
+    my $self = shift;
+    my ($cgi) = validate_pos( @_, { isa => 'CGI' } );
+    my $p = $cgi->path_info;
+
+    if ( $p =~ m|^/records\.json$| ) {
+        $self->_send_content(
+            content_type => 'text/x-json',
+            content      => to_json( $self->prophet_handle->enumerate_types )
+        );
+
+    } elsif ( $p =~ m|^/records/(.*)/(.*)/(.*)| ) {
+        my $type   = $1;
+        my $uuid   = $2;
+        my $prop   = $3;
+        my $record = $self->load_record( type => $type, uuid=> $uuid);
+        return $self->_send_404 unless($record);
+        if (my $val = $record->prop($prop)) {
+           return  $self->_send_content( content_type => 'text/plain', content => $val);
+        } else {
+            return $self->_send_404();
+        }
+    }
+    
+    elsif ( $p =~ m|^/records/(.*)/(.*).json| ) {
+        my $type   = $1;
+        my $uuid   = $2;
+        my $record = $self->load_record( type => $type, uuid=> $uuid);
+        return $self->_send_404 unless($record);
+        return $self->_send_content( content_type => 'text/x-json', content => to_json( $record->get_props ) );
+    }
+    
+    
+    elsif ( $p =~ m|^/records/(.*).json| ) {
+        my $type = $1;
+        my $col = Prophet::Collection->new( handle => $self->prophet_handle, type => $type );
+        $col->matching( sub {1} );
+        warn "Todo. query language";
+        return $self->_send_content(
+            content_type => 'text/x-json',
+            content      => to_json( { map { $_->uuid => "/records/$type/" . $_->uuid . ".json" } @$col } )
+            )
+
+    }
+}
+
+sub handle_request_post {
+    my $self = shift;
+    my ($cgi) = validate_pos( @_, { isa => 'CGI' } );
+    my $p = $cgi->path_info;
+    if ( $p =~ m|^/records/(.*)/(.*)/(.*)| ) {
+        my $type   = $1;
+        my $uuid   = $2;
+        my $prop   = $3;
+
+        my $record = $self->load_record( type => $type, uuid=> $uuid);
+        return $self->_send_404 unless($record);
+        $record->set_props( props => { $prop => ( $cgi->param('value') || undef ) } );
+        return $self->_send_redirect( to => "/records/$type/$uuid/$prop" );
+    } elsif ( $p =~ m|^/records/(.*)/(.*).json| ) {
+        my $type   = $1;
+        my $uuid   = $2;
+        my $record = $self->load_record( type => $type, uuid=> $uuid);
+
+        return $self->_send_404 unless($record);
+
+        my $ret = $record->set_props( props => { map { $_ => $cgi->param($_) } $cgi->param() } );
+        $self->_send_redirect( to => "/records/$type/$uuid.json" );
+    } elsif ( $p =~ m|^/records/(.*).json| ) {
+        my $type   = $1;
+        my $record = $self->load_record( type => $type);
+        my $uuid   = $record->create( props => { map { $_ => $cgi->param($_) } $cgi->param() } );
+        return $self->_send_redirect( to => "/records/$type/$uuid.json" );
+    }
+}
+
+sub load_record {
+    my $self = shift;
+    my %args = validate(@_, { type => 1, uuid => 0});
+
+        my $record = Prophet::Record->new( handle => $self->prophet_handle, type => $args{type} );
+        if ($args{'uuid'} ){
+        return undef unless ($self->prophet_handle->node_exists(type => $args{'type'}, uuid => $args{'uuid'}));
+        $record->load( uuid => $args{uuid} ) 
+        }
+        return $record;
+    }
+sub _send_content {
+    my $self = shift;
+    my %args = validate(@_, { content => 1, content_type => 1});
+    print "HTTP/1.0 200 OK\r\n";
+        print "Content-Type: ".$args{'content_type'}."\r\n";
+        print "Content-Length: ".length($args{'content'})."\r\n\r\n";
+        print $args{'content'};
+        return '200';
+}
+
+sub _send_404 {
+    my $self = shift;
+        print "HTTP/1.0 404 ENOFILE\r\n";
+        return '404';
+}
+
+sub _send_redirect {
+    my $self = shift;
+    my %args = validate(@_, { to => 1});
+        print "HTTP/1.0 302 Go over there\r\n";
+        print "Location: ".$args{'to'}."\r\n";
+        return '302';
+}
+
+
+
+1;

Modified: SVN-PropDB/t/resty-server.t
==============================================================================
--- SVN-PropDB/t/resty-server.t	(original)
+++ SVN-PropDB/t/resty-server.t	Mon Apr  7 14:38:35 2008
@@ -1,15 +1,16 @@
 #!/usr/bin/perl
-
+use warnings;
+use strict;
 BEGIN {
 use File::Temp qw(tempdir);
 $ENV{'PROPHET_REPO'} = tempdir( CLEANUP => 0 ) . '/repo-' . $$;
 
 };
 
-use Prophet::Test tests => 10;
+use Prophet::Test tests => 25;
 use Test::WWW::Mechanize;
+use JSON;
 my $ua = Test::WWW::Mechanize->new();
-
 my $cli = Prophet::CLI->new();
 my $s = Prophet::TestServer->new();
 $s->prophet_handle($cli->handle);
@@ -19,103 +20,74 @@
     return join("/",$url_root, at _);
 }
 
-$ua->get_ok(url('record-types.json'));
+$ua->get_ok(url('records.json'));
 is($ua->content, '[]');
 
 my $car = Prophet::Record->new(handle => $cli->handle, type => 'Cars');
 my ($uuid) = $car->create(props => { wheels => 4, windshields => 1 });
 ok($uuid, "Created record $uuid");
 
-$ua->get_ok(url('record-types.json'));
+$ua->get_ok(url('records.json'));
 is($ua->content, '["Cars"]');
 
 $ua->get_ok(url('records','Cars',$uuid.".json"));
 is($ua->content, '{"wheels":"4","windshields":"1"}');
 
 
+$ua->get(url('records','Cars',"1234.json"));
+is($ua->status, '404');
+
+
 $ua->post_ok(url('records','Cars',$uuid.".json"), { wheels => 6 } );
 
 $ua->get_ok(url('records','Cars',$uuid.".json"));
 is($ua->content, '{"wheels":"6","windshields":"1"}');
 
-$ua->put(url('records','Cars.json'), { wheels => 3, seatbelts => 'sure!' } );
 
-diag($ua->uri);
-diag($ua->content);
+$ua->post(url('records','Cars',"doesnotexist.json"), { wheels => 6 } );
+is($ua->status,'404', "Can't update a nonexistant car");
 
-package Prophet::Server;
-use base qw/HTTP::Server::Simple::CGI/;
-use Params::Validate qw/:all/;
-use JSON;
+$ua->post_ok(url('records','Cars.json'), { wheels => 3, seatbelts => 'sure!' } );
+my $new_uuid;
+if ($ua->uri =~ /Cars\/(.*)\.json/) { 
+    $new_uuid = $1;
+    ok($new_uuid, "Got the new record's uuid");
 
-sub prophet_handle {
-    my $self = shift;
-    $self->{'_prophet_handle'} = shift if (@_);
-    return $self->{'_prophet_handle'};
+} else {
+    ok(0, "Failed to get the new record's uri");
 }
 
+my $car2= Prophet::Record->new(handle => $cli->handle, type => 'Cars');
+$car2->load(uuid => $new_uuid);
+is_deeply($car2->get_props, { wheels => 3, seatbelts => 'sure!'}, "The thing we created remotely worked just great");
 
+diag("testing property-level access");
+$ua->get_ok(url('records','Cars',$uuid,'wheels'));
+is($ua->content, '6');
 
-sub handle_request {
-    my $self = shift;
-    my ($cgi) = validate_pos(@_, { isa=> 'CGI'});
-    
-    if (my $sub = $self->can('handle_request_'.lc($cgi->request_method))) {
-        $sub->($self, $cgi);
-    } else {
-        warn "Sorry, I don't know how to handle ".$cgi->request_method." requests.";
-    }   
-}
+$ua->post(url('records','Cars',$uuid,'wheels'), {value => 5});
+is($ua->content, '5', "Performing the update we get back the new response");
+diag($ua->uri);
+$ua->get_ok(url('records','Cars',$uuid,'wheels'));
+is($ua->content, '5', "The update worked");
 
-sub handle_request_get {
-    my $self = shift;
-    my ($cgi) = validate_pos(@_, { isa=> 'CGI'});
-    my $p = $cgi->path_info;  
-
-    if ( $p =~ m|^/record-types.json| ) {
-        print to_json($self->prophet_handle->enumerate_types); 
-
-    } elsif ( $p =~ m|^/records/(.*)/(.*).json| ) {
-        my $type = $1;
-        my $uuid = $2;
-        my $record = Prophet::Record->new( handle => $self->prophet_handle, type => $type);
-        $record->load(uuid => $uuid);
-        print to_json($record->get_props);
-    }
-}
+$ua->get(url('records','Cars',$uuid,'elephants'));
+is($ua->status, '404', "A car has no elephants yet, so the property returns 0");
 
-sub handle_request_put {
-    my $self = shift;
-    my ($cgi) = validate_pos(@_, { isa=> 'CGI'});
-    my $p = $cgi->path_info;  
-    if ( $p =~ m|^/records/(.*).json| ) {
-        my $type = $1;
-        my $record = Prophet::Record->new( handle => $self->prophet_handle, type => $type);
-        my $uuid = $record->create(props=> {map { $_ => $cgi->param($_) } $cgi->param()});
-    
-        print "302 Created\n";
-        print "Location: /records/$type/$uuid.json";
-    }
 
-}
-sub handle_request_post {
-    my $self = shift;
-    my ($cgi) = validate_pos(@_, { isa=> 'CGI'});
-    my $p = $cgi->path_info;  
-    if ( $p =~ m|^/records/(.*)/(.*).json| ) {
-        my $type = $1;
-        my $uuid = $2;
-        my $record = Prophet::Record->new( handle => $self->prophet_handle, type => $type);
-        $record->load(uuid => $uuid);
-        my $ret = $record->set_props( props => {map { $_ => $cgi->param($_) } $cgi->param()});
-        print "we should be returning some sort of resty code here";
-    }
-}
+diag("Now fetching a list of all the cars on the road");
+$ua->get_ok(url('records','Cars.json'));
+is_deeply(from_json($ua->content), { 
+        $uuid => '/records/Cars/'.$uuid.'.json',
+        $new_uuid => '/records/Cars/'.$new_uuid.'.json',
+    });
 
 
+$ua->get(url('some_crazy_page'));
+is($ua->status,'404', "No that page doesn't exist");
 
 
 package Prophet::TestServer;
-use base qw/Test::HTTP::Server::Simple Prophet::Server/;
+use base qw/Test::HTTP::Server::Simple Prophet::Server::REST/;
 
 1;



More information about the Bps-public-commit mailing list