Paws XXXXVI (The game she is over)
Well I left off on form my last post with this Moose error;
Attribute (Items) does not pass the type constraint because: Validation failed for 'ArrayRef[Str|Undef]' with value [ { Method: ARRAY(0x5184cf0) } ] at /wwwveh/lib/x86_64-linux-thread-multi/Moose/Object.pm line 24
but before I tackle that on I wanted to have a closer look at my changes I did to the callresult_class.tt template; I wanted to clean that up nicely and then my plan is to see if my changes have Borden anything else.
So in cleaning it up I found what might be a bug.
It seems that this call
[%- IF (stream_param or shape.payload == param_name) %]
is now out of the attributes foreach loop so I change things about a bit and now I just set a var in the template and apply the new trait if the var has a value;
+ [%- IF (shape.payload) %] [% has_payload=param_name %] [% END %]
[%- IF (c.required_in_shape(shape,param_name)) %], required => 1[% END %]);
+
[% END %]
- [%- IF (stream_param or shape.payload == param_name) %]
- use MooseX::ClassAttribute;
- [%- IF (stream_param) %]
- class_has _stream_param => (is => 'ro', default => '[% c.to_payload_shape_name(stream_param) %]');[% END %]
- [%- IF (shape.payload == param_name) %]
- class_has _payload => (is => 'ro', default => '[% param_name %]');[% END %]
- [%- END %]
+
has _request_id => (is => 'ro', isa => 'Str');
+ [%- IF (stream_param or has_payload ) %]
+ use MooseX::ClassAttribute;
+ [%- IF (stream_param) %]
+ class_has _stream_param => (is => 'ro', default => '[% c.to_payload_shape_name(stream_param) %]');[% END %]
+ [%- IF (has_payload) %]
+ class_has _payload => (is => 'ro', default => '[% has_payload %]');[% END %]
[%- END %]
and my class comes out nice and clean;
package Paws::CloudFront::GetDistributionResult;
use Moose;
has Distribution => (is => 'ro', isa => 'Paws::CloudFront::Distribution');
has ETag => (is => 'ro', isa => 'Str', traits => ['ParamInHeader'] , header_name => 'ETag' );
has _request_id => (is => 'ro', isa => 'Str');
use MooseX::ClassAttribute;
class_has _payload => (is => 'ro', default => 'Distribution');
1;
However this time round I did not get;
Attribute (Items) does not pass the type constraint because: Validation failed for 'ArrayRef[Str|Undef]'
I got;
Attribute (Id) is required at /wwwveh/lib/x86_64-linux-thread-multi/Moose/Object.pm line 24 Moose::Object::new('Paws::CloudFront::Origin') called at /home/scolesj/aws-sdk-perl/lib/Paws/Net/RestXMLResponse.pm line 300
I ran the test again got the same error but the next time I ran it I got a different error with no code changes in between.
Well I fortunately spotted what was going on here right away. It is a good old perl quirk that I know has caught me in the past and most likely caught many others as well.
'keys on a hash are not in a guaranteed order'
So my input hash is coming in one way but is not processed the same way so it looks like a different random error each time it ran.
Time for a little more debugging and I found that the best place for my debug code was near the very end of the 'new_from_result_struct' sub
}
++ warn("new args= $class=".Dumper(\%args));
$class->new(%args);
}
I do not think I have played in the sub yet in my PAWs adventure so I will give the 25c tour of what it does. It acts as a sort of coercion engine taking the passed params, looking at thier class meta attributes and then translates it into a new class.
Well the first thing I am going to do is set the 'sub new_from_result_struct' call up so it will return the same results each time. I can do that by simply adding a 'sort' in that sub;
--foreach my $att ($class->meta->get_attribute_list) {
++foreach my $att (sort($class->meta->get_attribute_list)) {
With that in place I can now have a look at my debug out put;
new= Paws::CloudFront::CachedMethods=$VAR1 = {
'Quantity' => '2',
'Items' => [
{
'Method' => [
'HEAD',
'GET'
]
}
]
};
with this error;
Attribute (Items) does not pass the type constraint because:
Validation failed for 'ArrayRef[Str|Undef]' with value [ { Method: ARRAY(0x54522f8) } ] at
/wwwveh/lib/x86_64-linux-thread-multi/Moose/Object.pm line 24
So lets get rid of that one;
I had a look in the class and my Items attributes is
has Items => (is => 'ro',
isa => 'ArrayRef[Str|Undef]',
request_name => 'Method',
list_request_name => 'Items',
traits => ['NameInRequest','ListNameInRequest'],
required => 1);
and I think I can work with that.
I checked in the boto and for 'Items' in 'CachedMethods'
I found
"Items":{
"shape":"MethodsList",
"documentation":"<p>A complex type that contains the HTTP methods that you want CloudFront to cache responses to.</p>"
}
Hmm and a MethodsList in boto is
"MethodsList":{
"type":"list",
"member":{
"shape":"Method",
"locationName":"Method"
}
},
which justs points to a string.
So what I want is a transform like this
'Items' => [
'HEAD',
'GET']
};
After adding in an absurdly large amount of debugging code to find the correct spot for the transform, all I needed was to do was add this in
++if ($meta->does("ListNameInRequest")){
++ $result->{$meta->{list_request_name}}= $result->{$meta->
{list_request_name}}->[0]->{$meta->request_name};
++ }
if ($meta->does("XMLAtribute")){
$args{ $key } = $result->{$meta->xml_attribute_name()};
}
elsif
in my sub but now I get a new error;
new= Paws::CloudFront::LoggingConfig=$VAR1 = {
'IncludeCookies' => 0,
'Enabled' => 0
};
Attribute (Prefix) is required at /wwwveh/lib/x86_64-linux-thread-multi/Moose/Object.pm line 24 Moose::Object::new('Paws::CloudFront::LoggingConfig', 'IncludeCookies', 0, 'Enabled', 0)
That leads me back to this generated class;
package Paws::CloudFront::LoggingConfig;
use Moose;
has Bucket => (is => 'ro', isa => 'Str' , required => 1);
has Enabled => (is => 'ro', isa => 'Bool' , required => 1);
has IncludeCookies => (is => 'ro', isa => 'Bool' , required => 1);
has Prefix => (is => 'ro', isa => 'Str' , required => 1);
all the fields are required which is great when I am putting stuff into the AWS API but in this case 'undef' is fine in any of the above as I am getting code back from the API and we can't control what is sent back.
So I think my only choice here is to set up a default value in the response.
That was easy enough as all I need to do was add this
}
elsif ($att_is_required){
$args{ $att } = "";
$args{ $att } = 0
if ($att_type eq 'Bool' or $att_type eq 'Int');
}
elsif
and I got rid of that error but ran into yet one more error;
can't locate object method "does" via package "HEAD" (perhaps
you forgot to load "HEAD"?) at /home/scolesj/aws-sdk-perl/auto-lib/Paws.pm line 155.
ouch that is in some auto generated code.
The head scratch-er here was I was getting all the classes correct such as;
'AllowedMethods' => bless( {
'Quantity' => '2',
'Items' => [
'HEAD',
'GET'
],
'CachedMethods' => bless( {
'Quantity' => '2',
'Items' => [
'HEAD',
'GET'
]
}, 'Paws::CloudFront::CachedMethods' )
}, 'Paws::CloudFront::AllowedMethods' ),
So I am a little concerned;
Time I think for my good old debugging buddy 'caller()'
I added this in
sub to_hash {
my (undef, $params) = @_;
my $refHash = {};
++my ($A,$B,$C) = caller();
++use Data::Dumper;
++warn("to_hash $A,$B,$C ".Dumper($params));
That led me back into the same sub and with a few more lines of debugging I found my answer. Seems I inadvertently made a typo in the 'Paws::CloudFront::CachedMethods' class when I was looking at it.
So I regenerated all my classes and presto things are working fine.
Now just get rid off all that debugging and clean up my code so I can move onto something else.
Leave a comment