File Coverage

blib/lib/WebService/NationBuilder/HTTP.pm
Criterion Covered Total %
statement 30 93 32.2
branch 0 12 0.0
condition 0 8 0.0
subroutine 10 23 43.4
pod 0 5 0.0
total 40 141 28.3


line stmt bran cond sub pod time code
1             package WebService::NationBuilder::HTTP;
2              
3 1     1   15576 use strict;
  1         2  
  1         50  
4 1     1   16 use warnings;
  1         4  
  1         36  
5              
6 1     1   1619 use Moo::Role;
  1         3  
  1         10  
7 1     1   1593 use HTTP::Request::Common qw(GET POST PUT DELETE);
  1         31047  
  1         516  
8 1     1   1111 use JSON qw(from_json to_json);
  1         15966  
  1         8  
9 1     1   1344 use LWP::UserAgent;
  1         29358  
  1         57  
10 1     1   13 use List::Util qw(any pairgrep);
  1         3  
  1         184  
11 1     1   12447 use Log::Any qw($log);
  1         12792  
  1         7  
12 1     1   111 use Carp qw(croak);
  1         3  
  1         76  
13 1     1   1434 use Try::Tiny;
  1         2180  
  1         1555  
14              
15             has timeout => (
16             is => 'ro',
17             default => 10,
18             );
19             has retries => (
20             is => 'ro',
21             default => 0,
22             );
23             has base_uri => (
24             is => 'ro',
25             lazy => 1,
26             default => sub {
27             my $self = shift;
28             return sprintf 'https://%s.%s/api/%s',
29             $self->subdomain, $self->domain, $self->version;
30             },
31             );
32              
33             my @qs_params = qw(page per_page total_pages email
34             first_name last_name phone mobile);
35              
36             around qw(http_get http_put http_post http_get_all) => sub {
37             my ($orig, $self, $path, $params) = @_;
38             croak 'Path is missing' unless $path;
39             return $self->$orig($path, $params, @_);
40             };
41              
42             sub http_get_all {
43 0     0 0   my ($self, $path, $params) = @_;
44 0           my $uri = $self->_request_uri($path, $params);
45 0           my @results;
46 0   0       $params ||= {};
47 0           $params->{page} = 1;
48 0           my $total_pages = 1;
49 0           while ($params->{page} <= $total_pages) {
50 0           my $content = $self->_req(GET $uri);
51 0           $total_pages = $content->{total_pages};
52 0           $params->{page}++;
53 0           $uri = $self->_request_uri($path, $params);
54 0           push @results, @{$content->{results}};
  0            
55             }
56 0           return \@results;
57             }
58              
59             sub http_get {
60 0     0 0   my ($self, $path, $params) = @_;
61 0           my $uri = $self->_request_uri($path, $params);
62 0           return $self->_req(GET $uri);
63             }
64              
65             sub http_post {
66 0     0 0   my ($self, $path, $body) = @_;
67 0           my $uri = $self->_request_uri($path);
68 0           return $self->_req(POST $uri, content => to_json $body);
69             }
70              
71             sub http_put {
72 0     0 0   my ($self, $path, $body) = @_;
73 0           my $uri = $self->_request_uri($path);
74 0           return $self->_req(PUT $uri, content => to_json $body);
75             }
76              
77             sub http_delete {
78 0     0 0   my ($self, $path) = @_;
79 0           my $uri = $self->_request_uri($path);
80 0           return $self->_req(DELETE $uri);
81             }
82              
83             sub _req {
84 0     0     my ($self, $req) = @_;
85 0           $req->header(authorization => ('Bearer '. $self->access_token));
86 0           $req->header(content_type => 'application/json');
87 0           $req->header(accept => 'application/json');
88 0           $self->_log_request($req);
89 0           my $res = $self->ua->request($req);
90 0           $self->_log_response($res);
91 0           my $retries = $self->retries;
92 0   0       while ($res->code =~ /^5/x and $retries--) {
93 0           sleep 1;
94 0           $res = $self->ua->request($req);
95             }
96 0 0         return if $res->code =~ /404|410/x;
97 0 0         return 1 if $res->code =~ /204/x;
98 0 0         return $res->content ? from_json($res->content) : 1;
99             }
100              
101             has ua => (
102             is => 'ro',
103             lazy => 1,
104             default => sub {
105             my $self = shift;
106             my $ua = LWP::UserAgent->new();
107             $ua->timeout($self->timeout);
108             return $ua;
109             },
110             );
111              
112             sub _request_uri {
113 0     0     my ($self, $path, $params) = @_;
114 0 0         my $uri = URI->new($path =~ /^http/x
115             ? $path
116             : $self->base_uri . '/' . $path);
117             $uri->query_form(
118 0 0 0 0     pairgrep { any { $a eq $_ } @qs_params } %{$params}
  0            
  0            
  0            
119             ) if $params && ref $params eq 'HASH';
120 0           return $uri;
121             }
122              
123             sub _log_content {
124 0     0     my ($self, $content) = @_;
125 0 0         if (length $content) {
126             try {
127 0     0     $content = to_json from_json $content;
128 0           $log->trace($content);
129             } catch {
130 0     0     $log->error('Invalid JSON: ' . $content);
131             }
132 0           }
133 0           return;
134             }
135              
136             sub _log_request {
137 0     0     my ($self, $req) = @_;
138 0           $log->trace($req->method . ' => ' . $req->uri);
139 0           _log_content $req->content;
140 0           return;
141             }
142              
143             sub _log_response {
144 0     0     my ($self, $res) = @_;
145 0           $log->trace($res->status_line);
146 0           my $content = $res->content;
147 0           _log_content $res->content;
148 0           return;
149             }
150              
151             1;
152              
153             __END__