Merge branch '8784-dir-listings'
[arvados.git] / sdk / perl / lib / Arvados / ResourceMethod.pm
index 577e4ea47ab29ea6c2305f121876aa48566b4a33..d7e86ffdd874996541107419e65e9a203745c255 100644 (file)
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
 package Arvados::ResourceMethod;
 use Carp;
 use Data::Dumper;
@@ -27,7 +31,18 @@ sub execute
 
     my %body_params;
     my %given_params = @_;
-    while (my ($param_name, $param) = each %{$method->{'parameters'}}) {
+    my %extra_params = %given_params;
+    my %method_params = %{$method->{'parameters'}};
+    if ($method->{'request'}->{'properties'}) {
+        while (my ($prop_name, $prop_value) =
+               each %{$method->{'request'}->{'properties'}}) {
+            if (ref($prop_value) eq 'HASH' && $prop_value->{'$ref'}) {
+                $method_params{$prop_name} = { 'type' => 'object' };
+            }
+        }
+    }
+    while (my ($param_name, $param) = each %method_params) {
+        delete $extra_params{$param_name};
         if ($param->{'required'} && !exists $given_params{$param_name}) {
             croak("Required parameter not supplied: $param_name");
         }
@@ -40,18 +55,37 @@ sub execute
         elsif ($param->{'type'} eq 'object') {
             my %param_value;
             my ($p, $v);
-            while (($property_name, $property) = each %{$param->{'properties'}}) {
-                if (!exists $given_params{$param_name}->{$property_name}) {
-                    ;
+            if (exists $param->{'properties'}) {
+                while (my ($property_name, $property) =
+                       each %{$param->{'properties'}}) {
+                    # if the discovery doc specifies object structure,
+                    # convert to true/false depending on supplied type
+                    if (!exists $given_params{$param_name}->{$property_name}) {
+                        ;
+                    }
+                    elsif (!defined $given_params{$param_name}->{$property_name}) {
+                        $param_value{$property_name} = JSON::null;
+                    }
+                    elsif ($property->{'type'} eq 'boolean') {
+                        $param_value{$property_name} = $given_params{$param_name}->{$property_name} ? JSON::true : JSON::false;
+                    }
+                    else {
+                        $param_value{$property_name} = $given_params{$param_name}->{$property_name};
+                    }
                 }
-                elsif ($given_params{$param_name}->{$property_name} eq undef) {
-                    $param_value{$property_name} = JSON::null;
-                }
-                elsif ($property->{'type'} eq 'boolean') {
-                    $param_value{$property_name} = $given_params{$param_name}->{$property_name} ? JSON::true : JSON::false;
-                }
-                else {
-                    $param_value{$property_name} = $given_params{$param_name}->{$property_name};
+            }
+            else {
+                while (my ($property_name, $property) =
+                       each %{$given_params{$param_name}}) {
+                    if (ref $property eq '' || $property eq undef) {
+                        $param_value{$property_name} = $property;
+                    }
+                    elsif (ref $property eq 'HASH') {
+                        $param_value{$property_name} = {};
+                        while (my ($k, $v) = each %$property) {
+                            $param_value{$property_name}->{$k} = $v;
+                        }
+                    }
                 }
             }
             $body_params{$param_name} = \%param_value;
@@ -61,8 +95,13 @@ sub execute
             $body_params{$param_name} = $given_params{$param_name};
         }
     }
+    if (%extra_params) {
+        croak("Unsupported parameter(s) passed to API call /$path: \"" . join('", "', keys %extra_params) . '"');
+    }
     my $r = $self->{'resourceAccessor'}->{'api'}->new_request;
-    $r->set_uri($self->{'resourceAccessor'}->{'api'}->{'discoveryDocument'}->{'baseUrl'} . "/" . $path);
+    my $base_uri = $self->{'resourceAccessor'}->{'api'}->{'discoveryDocument'}->{'baseUrl'};
+    $base_uri =~ s:/$::;
+    $r->set_uri($base_uri . "/" . $path);
     $r->set_method($method->{'httpMethod'});
     $r->set_auth_token($self->{'resourceAccessor'}->{'api'}->{'authToken'});
     $r->set_query_params(\%body_params) if %body_params;
@@ -70,7 +109,7 @@ sub execute
     my $data, $headers;
     my ($status_number, $status_phrase) = $r->get_status();
     if ($status_number != 200) {
-        croak("API call failed: $status_number $status_phrase\n". $r->get_body());
+        croak("API call /$path failed: $status_number $status_phrase\n". $r->get_body());
     }
     $data = $r->get_body();
     $headers = $r->get_headers();