From c9b6a1e574ff724c25ec9af6f2dd16e20c768fb6 Mon Sep 17 00:00:00 2001 From: Jess Robinson Date: Mon, 26 Jan 2015 11:05:57 +0000 Subject: [PATCH 1/2] Add initial versions of missing invoke method on set ability --- lib/WebAPI/DBIC/Resource/GenericSetInvoke.pm | 17 ++++ lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm | 84 ++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 lib/WebAPI/DBIC/Resource/GenericSetInvoke.pm create mode 100644 lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm diff --git a/lib/WebAPI/DBIC/Resource/GenericSetInvoke.pm b/lib/WebAPI/DBIC/Resource/GenericSetInvoke.pm new file mode 100644 index 0000000..4c1638f --- /dev/null +++ b/lib/WebAPI/DBIC/Resource/GenericSetInvoke.pm @@ -0,0 +1,17 @@ +package WebAPI::DBIC::Resource::GenericSetInvoke; + +=head1 NAME + +WebAPI::DBIC::Resource::GenericSetInvoke - a set of roles to implement a resource for making method calls on a DBIC item + +=cut + +use Moo; +use namespace::clean; + +extends 'WebAPI::DBIC::Resource::GenericCore'; +with 'WebAPI::DBIC::Resource::Role::Set', + 'WebAPI::DBIC::Resource::Role::SetInvoke', + ; + +1; diff --git a/lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm b/lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm new file mode 100644 index 0000000..27d5084 --- /dev/null +++ b/lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm @@ -0,0 +1,84 @@ +package WebAPI::DBIC::Resource::Role::SetInvoke; + +=head1 NAME + +WebAPI::DBIC::Resource::Role::SetInvoke - methods for resources representing method calls on item resources + +=cut + +use Scalar::Util qw(blessed); + +use Moo::Role; + + +requires 'decode_json'; +requires 'encode_json'; +requires 'render_item_as_plain_hash'; +requires 'throwable'; +requires 'set'; + +has method => ( + is => 'ro', + required => 1, +); + +sub post_is_create { return 0 } + +around 'allowed_methods' => sub { + return [ qw(POST) ]; +}; + + +sub process_post { + my $self = shift; + + # Here's we're calling a method on the item as a simple generic behaviour. + # This is very limited because, for example, the method has no knowledge + # that it's being called inside a web service, thus no way to do redirects + # or provide HTTP specific rich-exceptions. + # If anything more sophisticated is required then it should be implemented + # as a specific resource class for the method (or perhaps a role if there's + # a set of methods that require similar behaviour). + + # The POST body content provides a data structure containing the method arguments + # { args => [ (@_) ] } + $self->throwable->throw_bad_request(415, errors => "Request content-type not application/json") + unless $self->request->header('Content-Type') =~ 'application/.*?json'; + my $invoke_body_data = $self->decode_json($self->request->content); + $self->throwable->throw_bad_request(400, errors => "Request content not a JSON hash") + unless ref $invoke_body_data eq 'HASH'; + + my @method_args; + if (my $args = delete $invoke_body_data->{args}) { + $self->throwable->throw_bad_request(400, errors => "The args must be an array") + if ref $args ne 'ARRAY'; + @method_args = @$args; + } + $self->throwable->throw_bad_request(400, errors => "Unknown attributes: @{[ keys %$invoke_body_data ]}") + if keys %$invoke_body_data; + + my $method_name = $self->method; + # the method is expected to throw an exception on error. + my $result_raw = $self->item->$method_name(@method_args); + + my $result_rendered; + # return a DBIC resultset as array of hashes of ALL records (no paging) + if (blessed($result_raw) && $result_raw->isa('DBIx::Class::ResultSet')) { + $result_rendered = [ map { $self->render_item_as_plain_hash($_) } $result_raw->all ]; + } + # return a DBIC result row as a hash + elsif (blessed($result_raw) && $result_raw->isa('DBIx::Class::Row')) { + $result_rendered = $self->render_item_as_plain_hash($result_raw); + } + # return anything else as raw JSON wrapped in a hash + else { + # we shouldn't get an object here, but if we do then we + # stringify it here to avoid exposing the guts + $result_rendered = { result => (blessed $result_raw) ? "$result_raw" : $result_raw }; + } + + $self->response->body( $self->encode_json($result_rendered) ); + return 200; +} + +1; From 0f18a6d98095182b788c3e7ff5afc98631a23db1 Mon Sep 17 00:00:00 2001 From: Jess Robinson Date: Thu, 29 Jan 2015 12:26:46 +0000 Subject: [PATCH 2/2] Call SetInvoke on correct object --- lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm b/lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm index 27d5084..eb88fc9 100644 --- a/lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm +++ b/lib/WebAPI/DBIC/Resource/Role/SetInvoke.pm @@ -32,7 +32,7 @@ around 'allowed_methods' => sub { sub process_post { my $self = shift; - # Here's we're calling a method on the item as a simple generic behaviour. + # Here's we're calling a method on the set as a simple generic behaviour. # This is very limited because, for example, the method has no knowledge # that it's being called inside a web service, thus no way to do redirects # or provide HTTP specific rich-exceptions. @@ -59,7 +59,7 @@ sub process_post { my $method_name = $self->method; # the method is expected to throw an exception on error. - my $result_raw = $self->item->$method_name(@method_args); + my $result_raw = $self->set->$method_name(@method_args); my $result_rendered; # return a DBIC resultset as array of hashes of ALL records (no paging)