Search code examples
jsonperlcurlhttpresponselwp-useragent

Perl LWP::UserAgent parse response JSON


I am using the LWP::UserAgent module to issue a GET request to one of our APIs.

#!/usr/bin/perl
use strict;
use warning;
use LWP::UserAgent;
use Data::Dumper;

my $ua = LWP::UserAgent->new;
my $request = $ua->get("http://example.com/foo", Authorization => "Bearer abc123", Accept => "application/json" );

print Dumper $request->content;

The request is successful. Dumper returns the following JSON.

$VAR1 = '{
          "apiVersion": "v1",
          "data": {
              "ca-bundle.crt": "-----BEGIN CERTIFICATE-----abc123-----END CERTIFICATE-----\\n"
          },
          "kind": "ConfigMap",
          "metadata": {
              "creationTimestamp": "2021-07-16T17:13:01Z",
              "labels": {
                  "auth.openshift.io/managed-certificate-type": "ca-bundle"
              },
              "managedFields": [
                  {
                      "apiVersion": "v1",
                      "fieldsType": "FieldsV1",
                      "fieldsV1": {
                          "f:data": {
                              ".": {},
                              "f:ca-bundle.crt": {}
                          },
                          "f:metadata": {
                              "f:labels": {
                                  ".": {},
                                  "f:auth.openshift.io/managed-certificate-type": {}
                              }
                          }
                      },
                      "manager": "cluster-kube-apiserver-operator",
                      "operation": "Update",
                      "time": "2021-09-14T17:07:39Z"
                  }
              ],
              "name": "kube-control-plane-signer-ca",
              "namespace": "openshift-kube-apiserver-operator",
              "resourceVersion": "65461225",
              "selfLink": "/api/v1/namespaces/openshift-kube-apiserver-operator/configmaps/kube-control-plane-signer-ca",
              "uid": "f9aea067-1234-5678-9101-9d4073f5ae53"
          }
      }';

Let's say I want to print the value of the apiVersion key, which should print v1.

print "API Version = $request->content->{'apiVersion'} \n";

The following is being printed. I am not sure how to print the value v1. Since HTTP::Response is included in the output, I suspect I might have to use the HTTP::Response module?

API Version = HTTP::Response=HASH(0x2dffe80)->content->{'apiVersion'}

Solution

  • Perl doesn't expand subroutine calls in a double-quoted string.

    print "API Version = $request->content->{'apiVersion'} \n";
    

    In this line of code, content() is a subroutine call. So Perl sees this as:

    print "API Version = $request" . "->content->{'apiVersion'} \n";
    

    And if you try to print most Perl objects, you'll get the hash reference along with the name of the class - hence HTTP::Response=HASH(0x2dffe80).

    You might think that you just need to break up your print() statement like this:

    print 'API Version = ', $request->content->{'apiVersion'}, "\n";
    

    But that's not going to work either. $request->content doesn't return a Perl data structure, it returns a JSON-encoded string. You need to decode it into a data structure before you can access the individual elements.

    use JSON;
    
    print 'API Version = ', decode_json($request->content)->{'apiVersion'}, "\n";
    

    But it might be cleaner to do the decoding outside of the print() statement.

    use JSON;
    
    my $data = decode_json($request->content);
    

    In which case you can go back to something more like your original code:

    print "API Version = $data->{'apiVersion'} \n";