File Coverage

blib/lib/Device/WallyHome/Role/REST.pm
Criterion Covered Total %
statement 61 68 89.7
branch 9 16 56.2
condition 6 14 42.8
subroutine 14 15 93.3
pod 0 4 0.0
total 90 117 76.9


line stmt bran cond sub pod time code
1             package Device::WallyHome::Role::REST;
2 2     2   1505 use Moose::Role;
  2         4  
  2         15  
3 2     2   8679 use MooseX::AttributeShortcuts;
  2         4  
  2         36  
4              
5 2     2   4464 use Data::Dumper;
  2         5  
  2         132  
6 2     2   1478 use HTTP::Headers;
  2         13580  
  2         74  
7 2     2   939 use HTTP::Request;
  2         21865  
  2         70  
8 2     2   1059 use JSON::MaybeXS qw(decode_json);
  2         9768  
  2         129  
9 2     2   1354 use LWP::UserAgent;
  2         36302  
  2         77  
10              
11 2     2   1119 use Device::WallyHome::Test::Data;
  2         5  
  2         1403  
12              
13             our $VERSION = '0.21.3';
14              
15              
16             #== ATTRIBUTES =================================================================
17              
18             has 'apiHostname' => (
19             is => 'rw',
20             isa => 'Str',
21             default => 'api.snsr.net',
22             );
23              
24             has 'apiUseHttps' => (
25             is => 'rw',
26             isa => 'Int',
27             default => 1,
28             );
29              
30             has 'apiVersion' => (
31             is => 'rw',
32             isa => 'Str',
33             default => 'v2',
34             );
35              
36             has 'lastApiError' => (
37             is => 'ro',
38             isa => 'Maybe[Str]',
39             writer => '_lastApiError',
40             );
41              
42             has 'token' => (
43             is => 'rw',
44             isa => 'Str',
45             required => 1,
46             );
47              
48             has 'userAgentName' => (
49             is => 'lazy',
50             );
51              
52             has 'timeout' => (
53             is => 'rw',
54             isa => 'Int',
55             default => '180',
56             );
57              
58             has '_userAgent' => (
59             is => 'lazy',
60             );
61              
62             has '_testModeIdentifier' => (
63             is => 'rw',
64             isa => 'Maybe[Str]',
65             );
66              
67              
68             #== ATTRIBUTE BUILDERS =========================================================
69              
70             sub _build__userAgent {
71 0     0   0 my ($self) = @_;
72              
73 0         0 return LWP::UserAgent->new(
74             agent => $self->userAgentName(),
75             timeout => $self->timeout(),
76             );
77             }
78              
79             sub _build_userAgentName {
80 1     1   17 my $VERSION = Device::WallyHome->VERSION;
81              
82 1         35 return "Device::WallyHome v$VERSION";
83             }
84              
85              
86             #== PUBLIC METHODS =============================================================
87              
88             sub baseUrl {
89 2     2 0 3 my ($self) = @_;
90              
91 2 50       76 my $s = $self->apiUseHttps() ? 's' : '';
92              
93 2         66 return "http$s://" . $self->apiHostname() . '/' . $self->apiVersion() . '/';
94             }
95              
96             sub headers {
97 2     2 0 3 my ($self) = @_;
98              
99 2         22 my $headers = HTTP::Headers->new();
100              
101 2         86 $headers->header('Authorization' => 'Bearer ' . $self->token());
102              
103 2         111 return $headers;
104             }
105              
106             sub request {
107 2     2 0 4 my ($self, $params) = @_;
108              
109 2   50     6 $params //= {};
110              
111 2 50 33     15 die 'invalid params: ' . Dumper($params) unless ref($params) && ref($params) eq 'HASH';
112              
113 2   50     9 my $uri = $params->{uri} // die 'uri required';
114              
115 2   50     8 my $content = $params->{content} // undef;
116 2   33     18 my $headers = $params->{headers} // $self->headers();
117 2   50     10 my $method = $params->{method} // 'GET';
118              
119 2         9 my $request = HTTP::Request->new($method, $self->wallyUrl($uri), $headers, $content);
120              
121 2         7359 my $responseContent = undef;
122              
123 2 50       83 if (defined $self->_testModeIdentifier()) {
124             # Avoid actual API calls for automated testing
125 2         8 $responseContent = $self->_simulateTestResponse($uri);
126             } else {
127 0         0 my $response = $self->_userAgent()->request($request);
128              
129 0         0 $responseContent = $response->content();
130             }
131              
132 2         4 my $decodedResponse = {};
133              
134 2         3 eval {
135 2         134 $decodedResponse = decode_json($responseContent);
136             };
137              
138 2 50       9 if ($@) {
139 0         0 $self->_lastApiError($@);
140              
141 0         0 return undef;
142             }
143              
144 2         34 return $decodedResponse;
145             }
146              
147             sub _simulateTestResponse {
148 2     2   5 my ($self, $uri) = @_;
149              
150 2 50       64 die 'testModeIdentifier required' unless defined $self->_testModeIdentifier();
151              
152 2         79 my $testUtil = Device::WallyHome::Test::Data->new();
153              
154 2         5 my $testResponseFunc = 'sampleResponse_';
155              
156 2 100       13 if ($uri =~ /^places$/) {
    50          
157 1         3 $testResponseFunc .= 'places';
158             } elsif ($uri =~ /^places\/[^\/]+\/sensors/) {
159 1         2 $testResponseFunc .= 'sensors';
160             } else {
161 0         0 die "invalid/unexpected uri for testing: $uri";
162             }
163              
164 2         65 $testResponseFunc .= '_' . $self->_testModeIdentifier();
165              
166 2 50       22 die "invalid testResponseFunc: $testResponseFunc" unless $testUtil->can($testResponseFunc);
167              
168 2         11 return $testUtil->$testResponseFunc();
169             }
170              
171             sub wallyUrl {
172 2     2 0 4 my ($self, $path) = @_;
173              
174 2         6 return $self->baseUrl() . $path;
175             }
176              
177             1;