Search code examples
pythonrestperlput

Setting json string in http requests in Perl


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?


Solution

  • 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.