Business-TrueLayer
view release on metacpan or search on metacpan
lib/Business/TrueLayer/Request.pm view on Meta::CPAN
);
},
);
sub idempotency_key ( $self ) {
return Data::GUID->new->as_string;
}
sub api_post (
$self,
$absolute_path,
$http_request_body = undef,
$expect_json = 1,
) {
# sign the request
my $idempotency_key = $self->idempotency_key;
my $json = $http_request_body
? JSON->new->utf8->canonical->encode( $http_request_body )
: undef;
my ( $jws ) = $self->signer->sign_request(
'POST',
$absolute_path,
$idempotency_key,
$json,
);
return $self->_ua_request(
"https://" . $self->api_host . $absolute_path,
$json,
[
'Authorization' => "Bearer " . $self->authenticator->access_token,
'Tl-Signature' => $jws,
'Idempotency-Key' => $idempotency_key,
],
'POST',
$expect_json
);
}
sub _ua_request (
$self,
$url,
$body,
$headers = undef,
$method = 'POST',
$expect_json = 1
) {
my $ua = $self->_ua;
my $res = $ua->start($ua->build_tx(
$method,
$url,
{
'Accept' => 'application/json; charset=UTF-8',
'Content-Type' => 'application/json; charset=UTF-8',
@{ $headers // [] },
},
# Mojo::UserAgent::Transactor::tx calls $self->generators and then the
# callbacks based on the count of @_, and does not expect undef here
(defined $body ? ($body) : ()),
))->result;
# Easiest to deal with this first, even though it should be very rare:
if ( $res->code == 301 ) {
# possibly a redirect loop
croak( "TrueLayer $method $url failed > $MAX_REDIRECTS levels of redirect" );
}
if ( !$expect_json && !$res->is_success ) {
# All error responses are documented as returning JSON
$expect_json = 1;
}
my $code = $res->code;
# no content
return if $code == '204';
my $type = $res->headers->content_type;
croak( "TrueLayer $method $url returned $code with no MIME type" )
unless defined $type;
$body = $res->body;
return $body
if !$expect_json && $res->is_success;
# Either 2xx and expecting JSON, or an error response
croak( "TrueLayer $method $url returned $code $type not JSON, status line: "
. $res->message)
unless $type =~ m!\Aapplication/(?:problem\+)?JSON\b!i;
croak( "TrueLayer $method $url returned $code with an empty body" )
unless length $body;
my $res_content = try sub {
JSON->new->canonical->decode( $body );
},
catch_default sub {
croak( "TrueLayer $method $url returned $code with malformed JSON length @{[ length $body ]}: $_" );
};
croak( "TrueLayer $method $url returned $code JSON $res_content" )
unless ref $res_content eq 'HASH';
return $res_content
if $res->is_success;
# From here onward, it's all error handling, as best we can:
my $title = $res_content->{title};
if ( length $title ) {
# This is looking like an error format we expect:
# https://docs.truelayer.com/docs/payments-api-errors
my $detail = $res_content->{detail};
my $message = defined $detail ? "$title - $detail" : $title;
if ( $res_content->{errors} ) {
$message .= ' ';
$message .= join( "; ",$_->@* )
( run in 1.040 second using v1.01-cache-2.11-cpan-437f7b0c052 )