[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