1

Following Perl code generates an error printed below:

use strict;
use Data::Dumper;
use LWP::UserAgent;
use JSON;

my $token = 'my token';
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(PUT => "endpoint");
$req->header( 'Authorization' => "Bearer $token" );
$req->content_type('application/json');
$req->content('{"text":"whiteboard"}');
 
my $res = $ua->request($req);     
if ($res->is_success) {
    my $content = $res->decoded_content;
    my $fromjson = from_json($content);
    print Dumper $fromjson->{'results'}; 
}
else {
    print $res->status_line, "\n";
    print $res->content, "\n";
}

Error:

 {"detail":[{"loc":["body"],"msg":"str type expected","type":"type_error.str"}]}

However if I write the same code in Python, it works:

import requests
import os
import json

url = 'endpoint'
token='my token'

headers = {
            "Authorization": "Bearer "+token[:-1],
            "Content-type" : "application/json"
            }
res=requests.put(url, json='{"text":"whiteboard"}', headers=headers)
#res=requests.put(url, json='test string', headers=headers) # this also works
print('Response Content:\n',res)

What am I missing in the Perl code?

2
  • The Authorization token in the Python version is "my toke". In the perl version it's "my token". I don't think this is the root cause, but it is a difference. Commented Oct 11, 2023 at 23:27
  • Try printing $req->as_string to see what's actually being sent. Commented Oct 11, 2023 at 23:51

2 Answers 2

2

I believe Perl is sending the JSON object {"text":"whiteboard"}. Python is sending the JSON string "{\"text\":\"whiteboard\"}".

What the error is saying is the endpoint expects the body to be a JSON string, not a JSON object, so only the Python code works.

What you probably want is something like $req->content(q["a string"]). It's safer to encode it with a JSON encoder like in ikegami's answer.


In your Perl code, $req->content('{"text":"whiteboard"}') just sends the string {"text":"whiteboard"} as the body.

In your Python code, res=requests.put(url, json='{"text":"whiteboard"}', headers=headers) serializes the string {"text":"whiteboard"} into JSON. The body is a single JSON string "{\"text\":\"whiteboard\"}".

From the docs....

json – (optional) A JSON serializable Python object to send in the body of the Request.

If you wanted to send a JSON object you'd pass it a Python dict.

res=requests.put(url, json={"text":"whiteboard"}, headers=headers)

This should result in the same error.

Sign up to request clarification or add additional context in comments.

1 Comment

$req->content(q["a string"]). This works! Thanks!
2

The Perl equivalent would be

use Cpanel::JSON::XS qw( );

my $serializer = Cpanel::JSON::XS->new->utf8->allow_nonref;

$req->content( $serializer->encode( '{"text":"whiteboard"}' ) );

According to the docs (search for json=),

requests.put( url, json=payload )

is equivalent to

import json

headers={ 'Content-Type': 'application/json' }
requests.put( url, data=json.dumps( payload ), headers=headers )

In other words, the value provided to json is encoded using JSON. This means the following is the body of the message sent by the Python script:

"{\"text\":\"whiteboard\"}"

2 Comments

It is giving following error if I try your solution. hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this) at
So use the allow_nonref option.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.