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 )