Apertur-SDK

 view release on metacpan or  search on metacpan

lib/Apertur/SDK/HTTPClient.pm  view on Meta::CPAN

        my $err = $@;
        $self->{ua}->timeout($prev);
        die $err if $err;
    }
    else {
        $res = $self->{ua}->request($req);
    }
    my $status = $res->code;

    if ($status >= 400) {
        $self->_handle_error($res);
    }

    if ($status == 204) {
        return undef;
    }

    return decode_json($res->decoded_content);
}

sub request_raw {
    my ($self, $method, $path, %opts) = @_;

    my $url = $self->{base_url} . $path;
    my $headers = $opts{headers} || {};

    $headers->{'Authorization'} = $self->{auth_header}
        if $self->{auth_header};

    my $req = HTTP::Request->new(uc($method), $url);
    for my $key (keys %$headers) {
        $req->header($key => $headers->{$key});
    }

    my $res = $self->{ua}->request($req);
    my $status = $res->code;

    if ($status >= 400) {
        $self->_handle_error($res);
    }

    return $res->content;
}

sub _handle_error {
    my ($self, $res) = @_;
    my $status = $res->code;

    my $body = {};
    eval {
        $body = decode_json($res->decoded_content);
    };
    if ($@) {
        $body = { message => "HTTP $status" };
    }

    my $message = $body->{message} || "HTTP $status";
    my $code    = $body->{code};

    if ($status == 401) {
        Apertur::SDK::Error::Authentication->throw(message => $message);
    }
    elsif ($status == 404) {
        Apertur::SDK::Error::NotFound->throw(message => $message);
    }
    elsif ($status == 429) {
        my $retry_after = $res->header('Retry-After');
        $retry_after = defined $retry_after ? int($retry_after) : undef;
        Apertur::SDK::Error::RateLimit->throw(
            message     => $message,
            retry_after => $retry_after,
        );
    }
    elsif ($status == 400) {
        Apertur::SDK::Error::Validation->throw(message => $message);
    }
    else {
        Apertur::SDK::Error->throw(
            status_code => $status,
            code        => $code,
            message     => $message,
        );
    }
}

1;

__END__

=head1 NAME

Apertur::SDK::HTTPClient - HTTP wrapper for the Apertur API

=head1 SYNOPSIS

    use Apertur::SDK::HTTPClient;

    my $http = Apertur::SDK::HTTPClient->new(
        base_url => 'https://api.aptr.ca',
        api_key  => 'aptr_live_...',
    );

    my $data = $http->request('GET', '/api/v1/stats');
    my $raw  = $http->request_raw('GET', '/api/v1/upload-sessions/uuid/qr');

=head1 DESCRIPTION

Low-level HTTP client used internally by all Apertur SDK resource classes.
Handles JSON serialisation, bearer token authentication, multipart uploads,
and maps HTTP error responses to typed exception objects.

=head1 METHODS

=over 4

=item B<new(%args)>

Constructor. Accepts C<base_url>, C<api_key>, and C<oauth_token>.

=item B<request($method, $path, %opts)>

Sends a JSON API request and returns the decoded response as a hashref
or arrayref. Returns C<undef> for 204 No Content responses.

Options: C<body> (JSON string), C<headers> (hashref), C<multipart>
(arrayref for HTTP::Request::Common multipart POST), C<timeout> (per-request
override in seconds for the underlying LWP::UserAgent timeout).

=item B<request_raw($method, $path, %opts)>

Sends a request and returns the raw response body as a byte string.

=back

=cut



( run in 0.527 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )