Last updatedApr 23, 2018

Writing a REST client in Perl

This tutorial will write a Perl script which removes a user from all open reviews - this might be useful if a reviewer is no longer available, and is holding up the completed status of all their reviews.

First install the REST::Client and JSON packages from CPAN - the details of doing this will depend on your platform.

Data::Dumper is very useful when developing Perl REST clients:

1
print Dumper(from_json($client->responseContent()));

Our script will retrieve a list of all open reviews, get the uncompleted reviewers for each review, and if one of these matches the user passed as a command line parameter we will complete the reviewer.

  • Get all open reviews: GET /reviews-v1/filter/{filter}, setting {filter} to allOpenReviews.
  • Get the incomplete reviewers for each of these reviews: GET /reviews-v1/{id}/reviewers/uncompleted
  • Remove a reviewer: DELETE /reviews-v1/{id}/reviewers/{username}

When JSON produces lists of objects, the structures produced depend on the number of items in the list. If the /reviews-v1/filter URL returns a single review, the JSON will look like this:

1
2
3
4
 
{"reviews": 
    {"reviewData": {...attributes of review...}} 
} 

but if several reviews are returned the JSON will be:

1
2
3
4
 
{"reviews": 
    {"reviewData": [{...first review...},{...second review},...]} 
} 

and if there are no reviews it will simply be:

1
2
 
{"reviews": ""} 

The toList function in the code below handles the three cases above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use REST::Client;
use JSON;
# Data::Dumper makes it easy to see what the JSON returned actually looks like 
# when converted into Perl data structures.
use Data::Dumper;
use MIME::Base64;

sub toList {
   my $data = shift;
   my $key = shift;
   if (ref($data->{$key}) eq 'ARRAY') {
       $data->{$key};
   } elsif (ref($data->{$key}) eq 'HASH') {
       [$data->{$key}];
   } else {
       [];
   }
}
if ($#ARGV ne 0) {
    print "usage: $0 <username>\n";
    exit 1;
}
my $reviewerToRemove = $ARGV[0];
my $username = 'admin';
my $password = 'admin';
my $headers = {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)};
my $client = REST::Client->new();
$client->setHost('http://localhost:3990');
$client->GET(
    '/fecru/rest-service/reviews-v1/filter/allOpenReviews', 
    $headers
);
my $response = from_json($client->responseContent());
my $reviews = toList($response->{'reviews'},'reviewData');
foreach $review (@$reviews) {
    my $id = $review->{'permaId'}->{'id'};
    $client->GET(
        '/fecru/rest-service/reviews-v1/' . $id . '/reviewers/uncompleted', 
        $headers
    );
    my $response = from_json($client->responseContent());
    my $incompleteReviewers = toList($response->{'reviewers'},'reviewer');
    foreach $reviewer (@$incompleteReviewers) {
        $myreviewerUserName = $reviewer->{'userName'};
        if ($reviewerToRemove eq $myreviewerUserName) {
            print "Removing " . $reviewer->{'displayName'} . " from review " . $id . "\n";
            $client->DELETE(
                '/fecru/rest-service/reviews-v1/' . $id . '/reviewers/' . $reviewer->{'userName'}, 
                $headers
            );
            print Dumper($client->responseContent());
        }
    }
}