File Coverage

blib/lib/API/Client/Core.pm
Criterion Covered Total %
statement 27 27 100.0
branch n/a
condition n/a
subroutine 9 10 90.0
pod n/a
total 36 37 97.3


line stmt bran cond sub pod time code
1             # Client Core Class
2             package API::Client::Core;
3              
4 1     1   800 use namespace::autoclean -except => 'has';
  1         2  
  1         9  
5              
6 1     1   74 use Data::Object::Class;
  1         2  
  1         8  
7 1     1   320 use Data::Object::Class::Syntax;
  1         2  
  1         10  
8 1     1   254 use Data::Object::Signatures;
  1         2  
  1         10  
9              
10 1         6 use Data::Object::Library qw(
11             InstanceOf
12             Int
13 1     1   8194 );
  1         2  
14              
15 1     1   1543 use API::Client::Exception;
  1         3  
  1         41  
16              
17 1     1   36182 use Mojo::Transaction;
  1         425413  
  1         10  
18 1     1   25718 use Mojo::UserAgent;
  1         199794  
  1         11  
19 1     1   49 use Mojo::URL;
  1         2  
  1         5  
20              
21             our $VERSION = '0.02'; # VERSION
22              
23             # ATTRIBUTES
24              
25             has debug => rw;
26             has fatal => rw;
27             has retries => rw;
28             has timeout => rw;
29             has url => ro;
30             has user_agent => ro;
31              
32             # CONSTRAINTS
33              
34             opt debug => Int;
35             opt fatal => Int;
36             opt retries => Int;
37             opt timeout => Int;
38             opt url => InstanceOf['Mojo::URL'];
39             opt user_agent => InstanceOf['Mojo::UserAgent'];
40              
41             # DEFAULTS
42              
43             def debug => 0;
44             def fatal => 0;
45             def retries => 0;
46             def timeout => 10;
47             def user_agent => method { Mojo::UserAgent->new };
48              
49             # DELEGATES
50              
51             my @methods = qw(
52             DELETE
53             GET
54             HEAD
55             OPTIONS
56             PATCH
57             POST
58             PUT
59             );
60              
61             around [@methods] => fun ($orig, $self, %args) {
62             my $retries = $self->retries;
63             my $ua = $self->user_agent;
64              
65             # client timeouts
66             $ua->max_redirects(0);
67             $ua->connect_timeout($self->timeout);
68             $ua->request_timeout($self->timeout);
69              
70             # request defaults
71             $ua->on(start => fun ($ua, $tx) {
72             $self->PREPARE($ua, $tx, %args);
73             });
74              
75             # retry entry point
76             RETRY:
77              
78             # execute transaction
79             my $tx = $self->$orig(%args);
80             my $ok = $tx->res->code !~ /(4|5)\d\d/;
81              
82             # fetch transaction objects
83             my $req = $tx->req;
84             my $res = $tx->res;
85              
86             # attempt logging where applicable
87             if ($self->debug) {
88             my $reqstr = $req->to_string;
89             my $resstr = $res->to_string;
90              
91             $reqstr =~ s/\s*$/\n\n\n/;
92             $resstr =~ s/\s*$/\n\n\n/;
93              
94             print STDOUT $reqstr;
95             print STDOUT $resstr;
96             }
97              
98             # retry transaction where applicable
99             goto RETRY if $retries-- > 0 and not $ok;
100              
101             # throw exception if fatal is enabled
102             if ($self->fatal and not $ok) {
103             API::Client::Exception->throw(
104             tx => $tx,
105             code => $res->code,
106             method => $req->method,
107             url => $req->url,
108             );
109             }
110              
111             # return JSON
112             return $res->json;
113             };
114              
115             # METHODS
116              
117             method DELETE (Str :$path = '', HashRef :$data = {}, HashRef :$query = {}) {
118             my $ua = $self->user_agent;
119             my $url = $self->url->clone;
120              
121             $url->path(join '/', $url->path, $path) if $path;
122             $url->query($url->query->merge(%$query)) if keys %$query;
123              
124             return $ua->delete($url, ({}, keys(%$data) ? (json => $data) : ()));
125             }
126              
127       0     fun DESTROY {
128             ; # Protect subclasses using AUTOLOAD
129             }
130              
131             method GET (Str :$path = '', HashRef :$data = {}, HashRef :$query = {}) {
132             my $ua = $self->user_agent;
133             my $url = $self->url->clone;
134              
135             $url->path(join '/', $url->path, $path) if $path;
136             $url->query($url->query->merge(%$query)) if keys %$query;
137              
138             return $ua->get($url, ({}, keys(%$data) ? (json => $data) : ()));
139             }
140              
141             method HEAD (Str :$path = '', HashRef :$data = {}, HashRef :$query = {}) {
142             my $url = $self->url->clone;
143             my $ua = $self->user_agent;
144              
145             $url->path(join '/', $url->path, $path) if $path;
146             $url->query($url->query->merge(%$query)) if keys %$query;
147              
148             return $ua->head($url, ({}, keys(%$data) ? (json => $data) : ()));
149             }
150              
151             method OPTIONS (Str :$path = '', HashRef :$data = {}, HashRef :$query = {}) {
152             my $url = $self->url->clone;
153             my $ua = $self->user_agent;
154              
155             $url->path(join '/', $url->path, $path) if $path;
156             $url->query($url->query->merge(%$query)) if keys %$query;
157              
158             return $ua->options($url, ({}, keys(%$data) ? (json => $data) : ()));
159             }
160              
161             method PATCH (Str :$path = '', HashRef :$data = {}, HashRef :$query = {}) {
162             my $url = $self->url->clone;
163             my $ua = $self->user_agent;
164              
165             $url->path(join '/', $url->path, $path) if $path;
166             $url->query($url->query->merge(%$query)) if keys %$query;
167              
168             return $ua->patch($url, ({}, keys(%$data) ? (json => $data) : ()));
169             }
170              
171             method POST (Str :$path = '', HashRef :$data = {}, HashRef :$query = {}) {
172             my $url = $self->url->clone;
173             my $ua = $self->user_agent;
174              
175             $url->path(join '/', $url->path, $path) if $path;
176             $url->query($url->query->merge(%$query)) if keys %$query;
177              
178             return $ua->post($url, ({}, keys(%$data) ? (json => $data) : ()));
179             }
180              
181             method PUT (Str :$path = '', HashRef :$data = {}, HashRef :$query = {}) {
182             my $url = $self->url->clone;
183             my $ua = $self->user_agent;
184              
185             $url->path(join '/', $url->path, $path) if $path;
186             $url->query($url->query->merge(%$query)) if keys %$query;
187              
188             return $ua->put($url, ({}, keys(%$data) ? (json => $data) : ()));
189             }
190              
191             1;