File Coverage

blib/lib/WG/API/Base.pm
Criterion Covered Total %
statement 67 89 75.2
branch 13 26 50.0
condition 3 5 60.0
subroutine 17 20 85.0
pod 1 1 100.0
total 101 141 71.6


line stmt bran cond sub pod time code
1             package WG::API::Base;
2              
3 6     6   57957 use Modern::Perl '2015';
  6         16  
  6         54  
4 6     6   1056 use Moo::Role;
  6         12  
  6         42  
5              
6 6     6   4844 use WG::API::Error;
  6         18  
  6         235  
7 6     6   4408 use HTTP::Tiny;
  6         212575  
  6         250  
8 6     6   4281 use JSON;
  6         49468  
  6         52  
9 6     6   4433 use Data::Dumper;
  6         34928  
  6         393  
10 6     6   2538 use Log::Any qw($log);
  6         41461  
  6         38  
11 6     6   14857 use URI;
  6         27741  
  6         191  
12 6     6   3064 use URI::QueryParam;
  6         4757  
  6         8420  
13              
14             =encoding utf8
15              
16             =head1 VERSION
17              
18             Version v0.13
19              
20             =cut
21              
22             our $VERSION = 'v0.13';
23              
24             =head1 SYNOPSIS
25              
26             Base class for all instances
27              
28             =cut
29              
30             requires '_api_uri';
31              
32             =head1 ATTRIBUTES
33              
34             =over 1
35              
36             =item I<application_id*>
37              
38             Required application id: L<https://developers.wargaming.net/documentation/guide/getting-started/>
39              
40             =cut
41              
42             has application_id => (
43             is => 'ro',
44             require => 1,
45             );
46              
47             =item I<language>
48              
49             =cut
50              
51             has language => (
52             is => 'ro',
53             default => sub {'ru'},
54             );
55              
56             =item I<status>
57              
58             Return request status
59              
60             =cut
61              
62             has status => ( is => 'rw', );
63              
64             =item I<response>
65              
66             Return response
67              
68             =cut
69              
70             has response => ( is => 'rw', );
71              
72             =item I<meta_data>
73              
74             Return meta data from response
75              
76             =cut
77              
78             has meta_data => ( is => 'rw', );
79              
80             =item I<debug>
81              
82             Get current debug mode
83              
84             =back
85              
86             =cut
87              
88             has debug => (
89             is => 'rw',
90             writer => 'set_debug',
91             default => '0',
92             );
93              
94             =head1 METHODS
95              
96             =over 1
97              
98             =item B<ua>
99              
100             Returns a user agent instance
101              
102             =cut
103              
104             #@returns HTTP::Tiny
105             has ua => (
106             is => 'ro',
107             default => sub {
108             require HTTP::Tiny;
109             require IO::Socket::SSL;
110             HTTP::Tiny->new;
111             },
112             );
113              
114             =item B<error>
115              
116             Returns a WG::API::Error instance if defined;
117              
118             =cut
119              
120             #@returns WG::API::Error
121             has error => ( is => 'rw', );
122              
123             =item B<set_debug>
124              
125             Set debug mode
126              
127             =over 1
128              
129             =item B<log>
130              
131             Logger
132              
133             =back
134              
135             =back
136              
137             =cut
138              
139             sub log {
140 2     2 1 8 my ( $self, $event ) = @_;
141              
142 2 50       13 return unless $self->debug;
143              
144 2         28 $log->debug($event);
145             }
146              
147             sub _request {
148 1     1   8 my ( $self, $method, $uri, $params, $required_params, %passed_params ) = @_;
149              
150 1         6 $self->status(undef);
151              
152 1 50       6 unless ( $self->_validate_params( $required_params, %passed_params ) ) { #check required params
153 0         0 $self->status('error');
154 0         0 $self->error(
155             WG::API::Error->new(
156             code => '997',
157             message => 'missing a required field',
158             field => 'xxx',
159             value => 'xxx',
160             raw => 'xxx',
161             )
162             );
163 0         0 return;
164             }
165              
166 1         4 $method = "_" . $method; # add prefix for private methods
167              
168 1         7 $self->$method( $uri, $params, %passed_params );
169              
170 1 50       13 return $self->status eq 'ok' ? $self->response : undef;
171             }
172              
173             sub _validate_params {
174 1     1   3 my ( undef, $required_params, %passed_params ) = @_;
175              
176 1   50     5 $required_params //= [];
177 1 50       5 return if @$required_params > keys %passed_params;
178              
179 1         4 for (@$required_params) {
180 1 50       5 return unless defined $passed_params{$_};
181             }
182              
183 1         5 return 'passed';
184             }
185              
186             sub _get {
187 1     1   4 my ( $self, $uri, $params, %passed_params ) = @_;
188              
189             #@type HTTP::Response
190 1         5 my $response = $self->_raw_get( $self->_build_url($uri) . $self->_build_get_params( $params, %passed_params ) );
191              
192 1 50       459438 return $self->_parse( $response->{'status'} eq '200' ? decode_json $response->{'content'} : undef );
193             }
194              
195             sub _post {
196 0     0   0 my ( $self, $uri, $params, %passed_params ) = @_;
197              
198             #@type HTTP::Response
199 0         0 my $response = $self->_raw_post( $self->_build_url($uri), $self->_build_post_params( $params, %passed_params ) );
200              
201 0 0       0 return $self->_parse( $response->{'status'} eq '200' ? decode_json $response->{'content'} : undef );
202             }
203              
204             sub _parse {
205 1     1   4 my ( $self, $response ) = @_;
206              
207 1 50       8 if ( !$response ) {
    50          
208 0         0 $response = {
209             status => 'error',
210             error => {
211             code => '999',
212             message => 'invalid api_uri',
213             field => 'xxx',
214             value => 'xxx',
215             raw => Dumper $response,
216             },
217             };
218             }
219             elsif ( !$response->{'status'} ) {
220 0         0 $response = {
221             status => 'error',
222             error => {
223             code => '998',
224             message => 'unknown status',
225             field => 'xxx',
226             value => 'xxx',
227             raw => Dumper $response,
228             },
229             };
230             }
231              
232 1         10 $self->status( delete $response->{'status'} );
233              
234 1 50       8 if ( $self->status eq 'error' ) {
235 1         18 $self->error( WG::API::Error->new( $response->{'error'} ) );
236             }
237             else {
238 0         0 $self->error(undef);
239 0         0 $self->meta_data( $response->{'meta'} );
240 0         0 $self->response( $response->{'data'} );
241             }
242              
243 1         1840 $self->log( $self->error );
244              
245 1         81 return;
246             }
247              
248             #@returns URI;
249             sub _build_url {
250 1     1   3 my ( $self, $uri ) = @_;
251              
252 1         21 my $url = URI->new( $self->_api_uri );
253 1         5489 $url->scheme("https");
254 1         4085 $url->path($uri);
255              
256 1         60 return $url->as_string;
257             }
258              
259             sub _build_get_params {
260 1     1   14 my ( $self, $params, %passed_params ) = @_;
261              
262 1         5 my $url = URI->new( "", "https" );
263 1         101 $url->query_param( application_id => $self->application_id );
264 1         162 foreach my $param (@$params) {
265 5 100 66     177 $passed_params{$param} = $self->language if $param eq 'language' && !exists $passed_params{$param};
266 5 100       19 $url->query_param( $param => $passed_params{$param} ) if defined $passed_params{$param};
267             }
268              
269 1         179 return $url->as_string;
270             }
271              
272             sub _build_post_params {
273 0     0   0 my ( $self, $params, %passed_params ) = @_;
274              
275 0         0 my %params;
276 0         0 @params{ keys %passed_params } = ();
277 0         0 delete @params{@$params};
278 0         0 delete $passed_params{$_} for keys %params;
279              
280 0         0 $passed_params{'application_id'} = $self->application_id;
281 0 0       0 $passed_params{'language'} = $self->language unless exists $passed_params{'language'};
282              
283 0         0 return \%passed_params;
284             }
285              
286             sub _raw_get {
287 1     1   11 my ( $self, $url ) = @_;
288              
289 1         8 $self->log( sprintf "METHOD GET, URL: %s\n", $url );
290              
291 1         144 return $self->ua->get($url);
292             }
293              
294             sub _raw_post {
295 0     0     my ( $self, $url, $params ) = @_;
296              
297 0           $self->log( sprintf "METHOD POST, URL %s, %s\n", $url, Dumper $params );
298              
299 0           return $self->ua->post_form( $url, $params );
300             }
301              
302             =head1 BUGS
303              
304             Please report any bugs or feature requests to C<cynovg at cpan.org>, or through the web interface at L<https://gitlab.com/cynovg/WG-API/issues>. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
305              
306             =head1 SUPPORT
307              
308             You can find documentation for this module with the perldoc command.
309              
310             perldoc WG::API
311              
312             You can also look for information at:
313              
314             =over 4
315              
316             =item * RT: Gitlab's request tracker (report bugs here)
317              
318             L<https://gitlab.com/cynovg/WG-API/issues>
319              
320             =item * AnnoCPAN: Annotated CPAN documentation
321              
322             L<http://annocpan.org/dist/WG-API>
323              
324             =item * CPAN Ratings
325              
326             L<http://cpanratings.perl.org/d/WG-API>
327              
328             =item * Search CPAN
329              
330             L<https://metacpan.org/pod/WG::API>
331              
332             =back
333              
334              
335             =head1 ACKNOWLEDGEMENTS
336              
337             ...
338              
339             =head1 SEE ALSO
340              
341             WG API Reference L<https://developers.wargaming.net/>
342              
343             =head1 AUTHOR
344              
345             Cyrill Novgorodcev , C<< <cynovg at cpan.org> >>
346              
347             =head1 LICENSE AND COPYRIGHT
348              
349             Copyright 2015 Cyrill Novgorodcev.
350              
351             This program is free software; you can redistribute it and/or modify it
352             under the terms of the the Artistic License (2.0). You may obtain a
353             copy of the full license at:
354              
355             L<http://www.perlfoundation.org/artistic_license_2_0>
356              
357             Any use, modification, and distribution of the Standard or Modified
358             Versions is governed by this Artistic License. By using, modifying or
359             distributing the Package, you accept this license. Do not use, modify,
360             or distribute the Package, if you do not accept this license.
361              
362             If your Modified Version has been derived from a Modified Version made
363             by someone other than you, you are nevertheless required to ensure that
364             your Modified Version complies with the requirements of this license.
365              
366             This license does not grant you the right to use any trademark, service
367             mark, tradename, or logo of the Copyright Holder.
368              
369             This license includes the non-exclusive, worldwide, free-of-charge
370             patent license to make, have made, use, offer to sell, sell, import and
371             otherwise transfer the Package with respect to any patent claims
372             licensable by the Copyright Holder that are necessarily infringed by the
373             Package. If you institute patent litigation (including a cross-claim or
374             counterclaim) against any party alleging that the Package constitutes
375             direct or contributory patent infringement, then this Artistic License
376             to you shall terminate on the date that such litigation is filed.
377              
378             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
379             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
380             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
381             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
382             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
383             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
384             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
385             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
386              
387              
388             =cut
389              
390             1; # End of WG::API::Base