Group
Extension

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;


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.