File Coverage

blib/lib/Device/WallyHome/Role/REST.pm
Criterion Covered Total %
statement 59 67 88.0
branch 9 16 56.2
condition 6 14 42.8
subroutine 13 15 86.6
pod 0 4 0.0
total 87 116 75.0


line stmt bran cond sub pod time code
1             package Device::WallyHome::Role::REST;
2 2     2   1360 use Moose::Role;
  2         4  
  2         17  
3 2     2   8965 use MooseX::AttributeShortcuts;
  2         2  
  2         17  
4              
5 2     2   4341 use Data::Dumper;
  2         4  
  2         119  
6 2     2   1246 use HTTP::Headers;
  2         13668  
  2         69  
7 2     2   968 use HTTP::Request;
  2         21837  
  2         69  
8 2     2   955 use JSON::MaybeXS qw(decode_json);
  2         9614  
  2         118  
9 2     2   1307 use LWP::UserAgent;
  2         36545  
  2         72  
10              
11 2     2   964 use Device::WallyHome::Test::Data;
  2         6  
  2         1319  
12              
13             our $VERSION = 0.01;
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 0     0   0 return "Device::WallyHome v$VERSION";
81             }
82              
83              
84             #== PUBLIC METHODS =============================================================
85              
86             sub baseUrl {
87 2     2 0 5 my ($self) = @_;
88              
89 2 50       110 my $s = $self->apiUseHttps() ? 's' : '';
90              
91 2         118 return "http$s://" . $self->apiHostname() . '/' . $self->apiVersion() . '/';
92             }
93              
94             sub headers {
95 2     2 0 6 my ($self) = @_;
96              
97 2         30 my $headers = HTTP::Headers->new();
98              
99 2         133 $headers->header('Authorization' => 'Bearer ' . $self->token());
100              
101 2         182 return $headers;
102             }
103              
104             sub request {
105 2     2 0 5 my ($self, $params) = @_;
106              
107 2   50     9 $params //= {};
108              
109 2 50 33     69 die 'invalid params: ' . Dumper($params) unless ref($params) && ref($params) eq 'HASH';
110              
111 2   50     13 my $uri = $params->{uri} // die 'uri required';
112              
113 2   50     15 my $content = $params->{content} // undef;
114 2   33     16 my $headers = $params->{headers} // $self->headers();
115 2   50     14 my $method = $params->{method} // 'GET';
116              
117 2         16 my $request = HTTP::Request->new($method, $self->wallyUrl($uri), $headers, $content);
118              
119 2         7553 my $responseContent = undef;
120              
121 2 50       114 if (defined $self->_testModeIdentifier()) {
122             # Avoid actual API calls for automated testing
123 2         11 $responseContent = $self->_simulateTestResponse($uri);
124             } else {
125 0         0 my $response = $self->_userAgent()->request($request);
126              
127 0         0 $responseContent = $response->content();
128             }
129              
130 2         7 my $decodedResponse = {};
131              
132 2         6 eval {
133 2         198 $decodedResponse = decode_json($responseContent);
134             };
135              
136 2 50       11 if ($@) {
137 0         0 $self->_lastApiError($@);
138              
139 0         0 return undef;
140             }
141              
142 2         50 return $decodedResponse;
143             }
144              
145             sub _simulateTestResponse {
146 2     2   5 my ($self, $uri) = @_;
147              
148 2 50       115 die 'testModeIdentifier required' unless defined $self->_testModeIdentifier();
149              
150 2         146 my $testUtil = Device::WallyHome::Test::Data->new();
151              
152 2         5 my $testResponseFunc = 'sampleResponse_';
153              
154 2 100       23 if ($uri =~ /^places$/) {
    50          
155 1         3 $testResponseFunc .= 'places';
156             } elsif ($uri =~ /^places\/[^\/]+\/sensors/) {
157 1         5 $testResponseFunc .= 'sensors';
158             } else {
159 0         0 die "invalid/unexpected uri for testing: $uri";
160             }
161              
162 2         99 $testResponseFunc .= '_' . $self->_testModeIdentifier();
163              
164 2 50       23 die "invalid testResponseFunc: $testResponseFunc" unless $testUtil->can($testResponseFunc);
165              
166 2         13 return $testUtil->$testResponseFunc();
167             }
168              
169             sub wallyUrl {
170 2     2 0 5 my ($self, $path) = @_;
171              
172 2         8 return $self->baseUrl() . $path;
173             }
174              
175             1;