choroba has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to convert a curl API to Perl. I reached for Corion's HTTP::Request::FromCurl because I've used it successfully several times in the past.

The problem is with the -d option followed by a JSON string. For example, see Geneea API / Basic Calls:

curl -X POST https://api.geneea.com/v3/analysis \ -H 'Authorization: user_key <your user key>' \ -H 'Content-Type: application/json' \ -d '{"text": "The pizza in London was great!"}'

My code:

#!/usr/bin/perl use warnings; use strict; my $user_key = '...'; use HTTP::Request::FromCurl; use LWP::UserAgent; my $req = 'HTTP::Request::FromCurl'->new(argv => [ -X => POST => 'https://api.geneea.com/v3/analysis', -H => "Authorization: user_key $user_key", -H => 'Content-Type: application/json', -d => '{"text": "The pizza in London was great!"}', ]); my $ua = 'LWP::UserAgent'->new; my $response = $ua->request($req->as_request); use Data::Dumper; print Dumper($response);
But the response is a 400 containing an error message wrapping a stack trace that says among other things
JsonParseException: Unexpected character (\'\'\' (code 39))

Interestingly, if I build the request from the $req->as_snippet, it works correctly. Dumping the HTTP::Request objects created by the two methods shows one difference: the as_request method adds single quotes to the content:

'_content' => '\'{"text": "The pizza in London was great!"}\'',

I identified the part of the code responsible for the quotes: it's the line 93 in CurlParameters.pm:

return sprintf "'%s'", $body

When I remove the single quotes (or just return $body), it starts to work. Why are the single quotes needed here? What am I doing wrong?

map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

Replies are listed 'Best First'.
Re: Curl and Quoting JSON Data
by Corion (Patriarch) on Feb 26, 2019 at 17:33 UTC

    I think the main problem was that the subroutine in ::FromCurl is named ->_build_body when it should have been named ->_build_quoted_body. That in turn would make the programming error on my part obvious because the HTTP::Request object was built as:

    sub as_request( $self ) { HTTP::Request->new( $self->method => $self->uri, [ %{ $self->headers } ], $self->_build_quoted_body(), # was $self->_build_body ) };

    ... which is obviously wrong. ->_build_quoted_body should only be used when creating Perl code as output.

    The fix, on its way to CPAN in version 0.11, is to use the plain ->body:

    sub as_request( $self ) { HTTP::Request->new( $self->method => $self->uri, [ %{ $self->headers } ], $self->body(), ) };