Amazon-API
view release on metacpan or search on metacpan
lib/Amazon/API.pm view on Meta::CPAN
$request->header('X-Amz-Target', $self->get_target());
}
unless ($self->get_http_method eq 'GET') {
$options{content_type} = $options{content_type} || 'application/x-amz-json-1.1';
$request->content_type($options{content_type});
if ( $options{content_type} eq 'application/x-www-form-url-encoded') {
$options{content} = $self->_finalize_content($options{content});
}
$request->content($options{content});
}
else {
$request->uri(sprintf("%s?%s", $request->uri(), $self->_finalize_content($options{content})));
}
$request->header('X-Amz-Security-Token', $self->get_credentials->get_token)
if $self->get_credentials->get_token;
# sign the request
$self->get_signer->sign($request);
# make the request, return response object
if ( $self->get_debug ) {
print STDERR Dumper([$request]);
}
$self->get_user_agent->request($request);
}
sub _finalize_content {
my $self = shift;
my $content = shift;
my @args = $content if $content;
if ( $content && $content !~/Action=/ || ! $content ) {
push @args, "Action=" . $self->get_action;
}
if ( $self->get_version) {
push @args, "Version=" . $self->get_version
}
return @args ? join('&', @args) : '';
}
=pod
=head1 IMPLEMENTATION NOTES
=head2 X-Amz-Target
Most of the newer AWS APIs accept a header (X-Amz-Target) in lieu of
the CGI parameter Action. Some APIs also want the version in the
target, some don't. Sparse documentation about some of the nuances of
using the REST interface directly to call AWS APIs.
We use the C<api> value as a trigger to indicate we need to set the
Action in the X-Amz-Target header. We also check to see if the
version needs to be attached to the Action value as required by some
APIs.
if ( $self->get_api ) {
if ( $self->get_version) {
$self->set_target(sprintf("%s_%s.%s", $self->get_api, $self->get_version, $self->get_action));
}
else {
$self->set_target(sprintf("%s.%s", $self->get_api, $self->get_action));
}
$request->header('X-Amz-Target', $self->get_target());
}
DynamoDB & KMS seems to be able to use this in lieu of query variables
Action & Version, although again, there seems to be a lot of
inconsisitency in the APIs. DynamoDB uses DynamoDB_YYYYMMDD.Action
while KMS will not take the version that way and prefers
TrentService.Action (with no version). There is no explanation in any
of the documentations I have been able to find as to what
"TrentService" might actually mean.
In general, the AWS API ecosystem is very organic. Each service seems
to have its own rules and protocol regarding what the content of the
headers should be. This generic API interface tries to make it
possible to use a central class (Amazon::API) as a sort of gateway to
the APIs. The most generic interface is simply sending query variables
and not much else in the header. APIs like EC2 conform to the that
school, so as indicated above we use C<action> to determine whether to
send the API action in the header or to assume that it is being sent
as one of the query variables.
=head2 Rolling a new API
The class will stub out methods for the API if you pass an array of
API method names. The stub is equivalent to:
sub some_api {
my $self = shift;
$self ->invoke_api('SomeApi', @_);
}
Some will also be happy to know that the class will create an
equivalent CamelCase version of the method. If you choose to override
the method, you should override the snake case version of the method.
As an example, here is a possible implementation of
C<Amazon::CloudWatchEvents> that implements one of the API calls.
package Amazon::CloudWatchEvents;
use parent qw/Amazon::API/;
sub new {
my $class = shift;
my $options = shift || {};
$options->{api} 'AWSEvents';
( run in 0.857 second using v1.01-cache-2.11-cpan-e1769b4cff6 )