Net-Async-Spotify/lib/Net/Async/Spotify/API/Base.pm
package Net::Async::Spotify::API::Base;
use strict;
use warnings;
our $VERSION = '0.002'; # VERSION
our $AUTHORITY = 'cpan:VNEALV'; # AUTHORITY
use Future::AsyncAwait;
use Log::Any qw($log);
use Syntax::Keyword::Try;
use Scalar::Util qw(weaken isweak);
use URI;
use URI::QueryParam;
use JSON::MaybeUTF8 qw(:v1);
use Net::Async::Spotify::Object;
=head1 NAME
Net::Async::Spotify::API::Base - Base Package for Spotify API Classes.
=head1 DESCRIPTION
Base class to be used by all Autogenerated modules of Spotify API
=head1 METHODS
=cut
sub new {
my $self = bless { @_[1..$#_] }, $_[0];
die "Net::Async::Spotify has to be provided" unless $self->spotify and $self->spotify->isa('Net::Async::Spotify');
weaken($self->{spotify}) unless isweak($self->spotify);
$self->{mapping} = {};
return $self;
}
sub spotify { shift->{spotify} }
=head2 call_api
Calls Spotify API with the passed params.
Allowing also to accept user passed response type C<obj_type> as member of C<%args>
=cut
async sub call_api {
my ($self, $request, $response_objs, %args) = @_;
my ( $result, $request_headers, $request_uri, $request_content );
# Prepare needed response params.
# override if response type passed explicitly
$response_objs = [$args{obj_type}] if exists $args{obj_type};
# Path Parameter
if (my $path_parameter = $request->{param}{path_parameter} ) {
# Path parameters should be always required.
for my $key (keys $path_parameter->%*) {
unless ( exists $args{$key} ) {
$log->errorf('Required Path Parameter missing %s', $key);
return;
}
$request->{uri} = $request->{uri} =~ s/{$key}/$args{$key}/r;
}
}
$request_uri = URI->new($request->{uri});
# Headers; at the moment only Authorization
# Content header will be set only of content passed.
my $authorize = $request->{param}{header}{Authorization};
if ( $authorize and $authorize->{required} eq 'required' ) {
$request_headers->{Authorization} = $self->spotify->token->header_string;
}
# Unfortunately the API documentation is not consistent so check all possibilities.
if ( exists $request->{param}{header}{'Content-Type'}
or exists $request->{param}{json_body_parameter}
or $request->{method} eq 'POST'
) {
$request_content = {
content => {},
content_type => 'application/json',
};
}
# Query parameters
for my $qp (keys $request->{param}{query_parameter}->%*) {
$request_uri->query_param( $qp => $args{$qp} ) if exists $args{$qp};
# There is no need to confirm data Type
if ( !defined $request_uri->query_param($qp)
and $request->{param}{query_parameter}{$qp}{required} eq 'required') {
$log->errorf('Missing Required Query Parameter: %s', $qp);
return;
}
}
# Body parameters
for my $bp (keys $request->{param}{json_body_parameter}->%*) {
if ( exists $args{$bp} ) {
if ( $request->{param}{json_body_parameter}{$bp}{type} =~ /^array/ ) {
if ( ref($args{$bp}) eq 'ARRAY' ) {
$request_content->{content}{$bp} = $args{$bp};
} else {
push $request_content->{content}{$bp}->@*, split ',', $args{$bp};
}
} else {
$request_content->{content}{$bp} = $args{$bp};
}
} elsif ( $request->{param}{json_body_parameter}{$bp}{required} eq 'required' ) {
$log->errorf('Missing Required Body Parameter: %s', $bp);
return;
}
}
$request_content->{content} = encode_json_utf8($request_content->{content}) if exists $request_content->{content};
try {
$log->tracef('Requesting Spotify API: request: %s | uri: %s | content: %s', $request, $request_uri, $request_content);
$result = await $self->spotify->http->do_request(
method => $request->{method},
uri => $request_uri,
defined $request_content ? ($request_content->%*) : (),
headers => $request_headers,
);
$log->tracef('Spotify API response: %s', $result);
} catch ($e) {
use Data::Dumper;
$log->errorf('Error calling Spotify API request: %s | Error: %s', $request_uri->as_string, Dumper($e));
return;
}
if ( $result->content ) {
return {
status_line => $result->status_line,
content => $self->parse_response($self->decode_response($result->content), $response_objs)
};
}
return { status_line => $result->status_line, content => $result->content };
}
sub decode_response {
my ( $self, $content ) = @_;
try {
return decode_json_utf8($content);
} catch ($e) {
$log->warnf('Could not JSON decode Spotify API Response | Error: %s', $e);
return 0;
}
}
sub parse_response {
my ( $self, $decoded_res, $expected ) = @_;
$log->tracef('API Base Mapping: %s', $self->mapping);
try {
return $decoded_res ? Net::Async::Spotify::Object->new($decoded_res, $expected) : $decoded_res;
} catch ($e) {
$log->warnf('Could not Map Spotify API Response to its Object %s | Error: %s | data: %s', $expected, $e, $decoded_res);
return $decoded_res;
}
}
1;