--- /dev/null
+*.swp
+*.tar.gz
+Catalyst-Controller-DBIC-API*
- Remove debugging code from tests
- Fixed some typos and code cleanups
+- Added possibility to fetch a single object by id + tests using 'item'
+- Added item_root attribute which defaults to 'data' and is used as data root for 'item'
2.001003 2010-02-12 19:01:56 America/Chicago
return $row; # passthrough by default
}
+=method_protected item
+
+ :Private
+
+item will return a single object called by identifier in the uri. It will be inflated via each_object_inflate.
+
+=cut
+
+sub item :Private
+{
+ my ($self, $c) = @_;
+
+ if($c->req->count_objects != 1)
+ {
+ $c->log->error($_);
+ $self->push_error($c, { message => 'No objects on which to operate' });
+ $c->detach();
+ }
+ else
+ {
+ $c->stash->{response}->{$self->item_root} = $self->each_object_inflate($c, $c->req->get_object(0));
+ }
+}
+
+
=method_protected update_or_create
:Private
By default provides the following endpoints:
- $base (accepts PUT and GET)
- $base/[identifier] (accepts POST and DELETE)
+ $base (operates on lists of objects and accepts GET, PUT, POST and DELETE)
+ $base/[identifier] (operates on a single object and accepts GET, PUT, POST and DELETE)
Where $base is the URI described by L</setup>, the chain root of the controller, and the request type will determine the L<Catalyst::Controller::DBIC::API> method to forward.
...
);
-=method_protected base
+=method_protected no_id
-Chained: L</setup>
+Chained: L</object_no_id>
PathPart: none
CaptureArgs: 0
Forwards to list level methods described in L<Catalyst::Controller::DBIC::API> as follows:
-DELETE: forwards to L<Catalyst::Controller::DBIC::API/object> then L<Catalyst::Controller::DBIC::API/delete>
-POST/PUT: forwards to L<Catalyst::Controller::DBIC::API/object> then L<Catalyst::Controller::DBIC::API/update_or_create>
+DELETE: L<Catalyst::Controller::DBIC::API/delete>
+POST/PUT: L<Catalyst::Controller::DBIC::API/update_or_create>
GET: forwards to L<Catalyst::Controller::DBIC::API/list>
=cut
$c->forward('list');
}
+=method_protected with_id
+
+Chained: L</object_with_id>
+PathPart: none
+CaptureArgs: 0
+
+Forwards to list level methods described in L<Catalyst::Controller::DBIC::API> as follows:
+
+DELETE: L<Catalyst::Controller::DBIC::API/delete>
+POST/PUT: L<Catalyst::Controller::DBIC::API/update_or_create>
+GET: forwards to L<Catalyst::Controller::DBIC::API/item>
+
+=cut
+
sub with_id :Chained('object_with_id') :PathPart('') :ActionClass('REST') :CaptureArgs(0) {}
sub with_id_PUT
$base/create
$base/list
+ $base/id/[identifier]
$base/id/[identifier]/delete
$base/id/[identifier]/update
...
);
-=method_protected object
-
-Chained: L</setup>
-PathPart: object
-CaptureArgs: 1
-
-Provides an chain point to the functionality described in L<Catalyst::Controller::DBIC::API/object>. All object level endpoints should use this as their chain root.
-
=cut
sub index : Chained('setup') PathPart('') Args(0) {
=method_protected create
-Chained: L</setup>
+Chained: L</object_no_id>
PathPart: create
CaptureArgs: 0
=cut
-sub create :Chained('setup') :PathPart('create') :Args(0)
+sub create :Chained('object_no_id') :PathPart('create') :Args(0)
{
my ($self, $c) = @_;
- $c->forward('object');
- return if $self->get_errors($c);
$c->forward('update_or_create');
}
=method_protected list
-Chained: L</setup>
+Chained: L</deserialize>
PathPart: list
CaptureArgs: 0
=cut
-sub list :Chained('setup') :PathPart('list') :Args(0) {
+sub list :Chained('deserialize') :PathPart('list') :Args(0) {
my ($self, $c) = @_;
$self->next::method($c);
}
+=method_protected item
+
+Chained: L</object_with_id>
+PathPart: ''
+Args: 0
+
+Provides an endpoint to the functionality described in L<Catalyst::Controller::DBIC::API/item>.
+
+=cut
+
+sub item :Chained('object_with_id') :PathPart('') :Args(0) {
+ my ($self, $c) = @_;
+
+ $c->forward('view');
+}
+
=method_protected update
-Chained: L</object>
+Chained: L</object_with_id>
PathPart: update
-CaptureArgs: 0
+Args: 0
Provides an endpoint to the functionality described in L<Catalyst::Controller::DBIC::API/update_or_create>.
=cut
-sub update :Chained('object') :PathPart('update') :Args(0) {
- my ($self, $c) = @_;
+sub update :Chained('object_with_id') :PathPart('update') :Args(0) {
+ my ($self, $c) = @_;
$c->forward('update_or_create');
}
=method_protected delete
-Chained: L</object>
+Chained: L</object_with_id>
PathPart: delete
-CaptureArgs: 0
+Args: 0
Provides an endpoint to the functionality described in L<Catalyst::Controller::DBIC::API/delete>.
=cut
-sub delete :Chained('object') :PathPart('delete') :Args(0) {
- my ($self, $c) = @_;
+sub delete :Chained('object_with_id') :PathPart('delete') :Args(0)
+{
+ my ($self, $c) = @_;
+ $self->next::method($c);
+}
- $self->next::method($c);
+=method_protected update_bulk
+
+Chained: L</object_no_id>
+PathPart: update
+Args: 0
+
+Provides an endpoint to the functionality described in L<Catalyst::Controller::DBIC::API/update_or_create> for multiple objects.
+
+=cut
+
+sub update_bulk :Chained('object_no_id') :PathPart('update') :Args(0)
+{
+ my ($self, $c) = @_;
+ $c->forward('update_or_create');
+}
+
+=method_protected delete_bulk
+
+Chained: L</object_no_id>
+PathPart: delete
+Args: 0
+
+Provides an endpoint to the functionality described in L<Catalyst::Controller::DBIC::API/delete> for multiple objects.
+
+=cut
+
+sub delete_bulk :Chained('object_no_id') :PathPart('delete') :Args(0)
+{
+ my ($self, $c) = @_;
+ $self->next::method($c);
}
1;
count_objects => 'count',
has_objects => 'count',
clear_objects => 'clear',
+ get_object => 'get',
},
);
has 'data_root' => ( is => 'ro', isa => Str, default => 'list');
+=attribute_public item_root is: ro, isa: Str, default: 'data'
+
+item_root controls how to reference where the data for single object
+requests is in the the request_data
+
+=cut
+
+has 'item_root' => ( is => 'ro', isa => Str, default => 'data');
+
=attribute_public total_entries_arg is: ro, isa: Str, default: 'totalcount'
total_entries_arg controls how to reference 'total_entries' in the the request_data
--- /dev/null
+use 5.6.0;
+
+use strict;
+use warnings;
+
+use lib 't/lib';
+
+my $base = 'http://localhost';
+
+use RestTest;
+use DBICTest;
+use URI;
+use Test::More;
+use Test::WWW::Mechanize::Catalyst 'RestTest';
+use HTTP::Request::Common;
+use JSON::Any;
+
+my $mech = Test::WWW::Mechanize::Catalyst->new;
+ok(my $schema = DBICTest->init_schema(), 'got schema');
+
+my $artist_view_url = "$base/api/rest/artist/";
+
+{
+ my $id = 1;
+ my $req = GET( $artist_view_url . $id, undef, 'Accept' => 'application/json' );
+ $mech->request($req);
+ cmp_ok( $mech->status, '==', 200, 'open attempt okay' );
+ my %expected_response = $schema->resultset('Artist')->find($id)->get_columns;
+ my $response = JSON::Any->Load( $mech->content);
+ is_deeply( $response, { data => \%expected_response, success => 'true' }, 'correct data returned' );
+}
+
+{
+ my $id = 5;
+ my $req = GET( $artist_view_url . $id, undef, 'Accept' => 'application/json' );
+ $mech->request($req);
+ cmp_ok( $mech->status, '==', 400, 'open attempt not ok' );
+ my $response = JSON::Any->Load( $mech->content);
+ is($response->{success}, 'false', 'not existing object fetch failed ok');
+ like($response->{messages}->[0], qr/^No object found for id/, 'error message for not existing object fetch ok');
+}
+
+done_testing();
--- /dev/null
+use 5.6.0;
+
+use strict;
+use warnings;
+
+use lib 't/lib';
+
+my $base = 'http://localhost';
+
+use RestTest;
+use DBICTest;
+use URI;
+use Test::More;
+use Test::WWW::Mechanize::Catalyst 'RestTest';
+use HTTP::Request::Common;
+use JSON::Any;
+
+my $mech = Test::WWW::Mechanize::Catalyst->new;
+ok(my $schema = DBICTest->init_schema(), 'got schema');
+
+my $artist_view_url = "$base/api/rpc/artist/id/";
+
+{
+ my $id = 1;
+ my $req = GET( $artist_view_url . $id, undef, 'Accept' => 'application/json' );
+ $mech->request($req);
+ cmp_ok( $mech->status, '==', 200, 'open attempt okay' );
+ my %expected_response = $schema->resultset('Artist')->find($id)->get_columns;
+ my $response = JSON::Any->Load( $mech->content);
+ is_deeply( $response, { data => \%expected_response, success => 'true' }, 'correct data returned' );
+}
+
+{
+ my $id = 5;
+ my $req = GET( $artist_view_url . $id, undef, 'Accept' => 'application/json' );
+ $mech->request($req);
+ cmp_ok( $mech->status, '==', 400, 'open attempt not ok' );
+ my $response = JSON::Any->Load( $mech->content);
+ is($response->{success}, 'false', 'not existing object fetch failed ok');
+ like($response->{messages}->[0], qr/^No object found for id/, 'error message for not existing object fetch ok');
+}
+
+done_testing();