File Coverage

lib/Smartcat/Client/ApiClient.pm
Criterion Covered Total %
statement 57 171 33.3
branch 1 78 1.2
condition 2 33 6.0
subroutine 18 33 54.5
pod 0 14 0.0
total 78 329 23.7


line stmt bran cond sub pod time code
1              
2             =begin comment
3              
4             Smartcat Integration API
5              
6             No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
7              
8             OpenAPI spec version: v1
9              
10             Generated by: https://github.com/swagger-api/swagger-codegen.git
11              
12             =end comment
13              
14             =cut
15              
16             #
17             # NOTE: This class is auto generated by the swagger code generator program.
18             # Do not edit the class manually.
19             # Ref: https://github.com/swagger-api/swagger-codegen
20             #
21             package Smartcat::Client::ApiClient;
22              
23 11     11   79 use strict;
  11         24  
  11         361  
24 11     11   57 use warnings;
  11         25  
  11         311  
25 11     11   58 use utf8;
  11         17  
  11         60  
26              
27 11     11   5420 use MIME::Base64;
  11         6988  
  11         644  
28 11     11   7474 use LWP::UserAgent;
  11         507836  
  11         446  
29 11     11   236 use HTTP::Headers;
  11         21  
  11         265  
30 11     11   115 use HTTP::Response;
  11         23  
  11         318  
31 11     11   5878 use HTTP::Request::Common qw(DELETE POST GET HEAD PUT);
  11         25343  
  11         897  
32 11     11   89 use HTTP::Status;
  11         19  
  11         2831  
33 11     11   5378 use URI::Query;
  11         24061  
  11         552  
34 11     11   5724 use JSON;
  11         73516  
  11         65  
35 11     11   1553 use URI::Escape;
  11         22  
  11         537  
36 11     11   57 use Scalar::Util;
  11         21  
  11         398  
37 11     11   60 use Log::Any qw($log);
  11         18  
  11         93  
38 11     11   3177 use Carp;
  11         24  
  11         589  
39 11     11   5360 use Module::Runtime qw(use_module);
  11         16833  
  11         63  
40              
41 11     11   4951 use Smartcat::Client::Configuration;
  11         32  
  11         20752  
42              
43             sub new {
44 11     11 0 41 my $class = shift;
45              
46 11         14 my $config;
47 11 50 33     60 if ( $_[0] && ref $_[0] && ref $_[0] eq 'Smartcat::Client::Configuration' )
      33        
48             {
49 0         0 $config = $_[0];
50             }
51             else {
52 11         66 $config = Smartcat::Client::Configuration->new(@_);
53             }
54              
55 11         82 my (%args) = (
56             'ua' => LWP::UserAgent->new,
57             'config' => $config,
58             );
59              
60 11         32486 return bless \%args, $class;
61             }
62              
63             # Set the user agent of the API client
64             #
65             # @param string $user_agent The user agent of the API client
66             #
67             sub set_user_agent {
68 0     0 0   my ( $self, $user_agent ) = @_;
69 0           $self->{http_user_agent} = $user_agent;
70             }
71              
72             # Set timeout
73             #
74             # @param integer $seconds Number of seconds before timing out [set to 0 for no timeout]
75             #
76             sub set_timeout {
77 0     0 0   my ( $self, $seconds ) = @_;
78 0 0         if ( !looks_like_number($seconds) ) {
79 0           croak('Timeout variable must be numeric.');
80             }
81 0           $self->{http_timeout} = $seconds;
82             }
83              
84             # make the HTTP request
85             # @param string $resourcePath path to method endpoint
86             # @param string $method method to call
87             # @param array $queryParams parameters to be place in query URL
88             # @param array $postData parameters to be placed in POST body
89             # @param array $headerParams parameters to be place in request header
90             # @return mixed
91             sub _call_api {
92 0     0     my $self = shift;
93             my (
94 0           $resource_path, $method, $query_params, $post_params,
95             $header_params, $body_data, $auth_settings
96             ) = @_;
97              
98             # update parameters based on authentication settings
99 0           $self->update_params_for_auth( $header_params, $query_params,
100             $auth_settings );
101              
102 0           my $_url = $self->{config}{base_url} . $resource_path;
103              
104             # build query
105 0 0         if (%$query_params) {
106             $_url =
107 0           ( $_url . '?' . eval { URI::Query->new($query_params)->stringify } );
  0            
108             }
109              
110             # body data
111 0 0 0       $body_data = to_json( $body_data->to_hash )
      0        
112             if defined $body_data
113             && ref $body_data ne 'ARRAY'
114             && $body_data->can('to_hash'); # model to json string
115 0 0         my $_body_data = %$post_params ? $post_params : $body_data;
116              
117             # Make the HTTP request
118 0           my $_request;
119 0 0         if ( $method eq 'POST' ) {
    0          
    0          
    0          
    0          
    0          
120              
121             # multipart
122             $header_params->{'Content-Type'} =
123             lc $header_params->{'Content-Type'} eq 'multipart/form-data'
124             ? 'form-data'
125 0 0         : $header_params->{'Content-Type'};
126              
127 0           $_request = POST( $_url, %$header_params, Content => $_body_data );
128              
129             }
130             elsif ( $method eq 'PUT' ) {
131              
132             # multipart
133             $header_params->{'Content-Type'} =
134             lc $header_params->{'Content-Type'} eq 'multipart/form-data'
135             ? 'form-data'
136 0 0         : $header_params->{'Content-Type'};
137              
138 0           $_request = PUT( $_url, %$header_params, Content => $_body_data );
139              
140             }
141             elsif ( $method eq 'GET' ) {
142 0           my $headers = HTTP::Headers->new(%$header_params);
143 0           $_request = GET( $_url, %$header_params );
144             }
145             elsif ( $method eq 'HEAD' ) {
146 0           my $headers = HTTP::Headers->new(%$header_params);
147 0           $_request = HEAD( $_url, %$header_params );
148             }
149             elsif ( $method eq 'DELETE' ) { #TODO support form data
150 0           my $headers = HTTP::Headers->new(%$header_params);
151 0           $_request = DELETE( $_url, %$headers );
152             }
153             elsif ( $method eq 'PATCH' ) { #TODO
154             }
155             else {
156             }
157              
158             $self->{ua}
159 0   0       ->timeout( $self->{http_timeout} || $self->{config}{http_timeout} );
160             $self->{ua}
161 0   0       ->agent( $self->{http_user_agent} || $self->{config}{http_user_agent} );
162              
163 0           $log->debugf( "REQUEST: %s", $_request->as_string );
164 0           my $_response = $self->{ua}->request($_request);
165 0           $log->debugf( "RESPONSE: %s", $_response->as_string );
166              
167 0 0         unless ( $_response->is_success ) {
168 0           croak( sprintf "API Exception(%s): %s\n%s",
169             $_response->code, $_response->message, $_response->content );
170             }
171              
172 0           return $_response;
173             }
174              
175             sub call_api {
176 0     0 0   my $self = shift;
177 0           return $self->_call_api(@_)->content;
178             }
179              
180             # Take value and turn it into a string suitable for inclusion in
181             # the path, by url-encoding.
182             # @param string $value a string which will be part of the path
183             # @return string the serialized object
184             sub to_path_value {
185 0     0 0   my ( $self, $value ) = @_;
186 0           return uri_escape( $self->to_string($value) );
187             }
188              
189             # Take value and turn it into a string suitable for inclusion in
190             # the query, by imploding comma-separated if it's an object.
191             # If it's a string, pass through unchanged. It will be url-encoded
192             # later.
193             # @param object $object an object to be serialized to a string
194             # @return string the serialized object
195             sub to_query_value {
196 0     0 0   my ( $self, $object ) = @_;
197 0 0         if ( ref($object) eq 'ARRAY' ) {
198 0           return join( ',', @$object );
199             }
200             else {
201 0           return $self->to_string($object);
202             }
203             }
204              
205             # Take value and turn it into a string suitable for inclusion in
206             # the header. If it's a string, pass through unchanged
207             # If it's a datetime object, format it in ISO8601
208             # @param string $value a string which will be part of the header
209             # @return string the header string
210             sub to_header_value {
211 0     0 0   my ( $self, $value ) = @_;
212 0           return $self->to_string($value);
213             }
214              
215             # Take value and turn it into a string suitable for inclusion in
216             # the http body (form parameter). If it's a string, pass through unchanged
217             # If it's a datetime object, format it in ISO8601
218             # @param string $value the value of the form parameter
219             # @return string the form string
220             sub to_form_value {
221 0     0 0   my ( $self, $value ) = @_;
222 0           return $self->to_string($value);
223             }
224              
225             # Take value and turn it into a string suitable for inclusion in
226             # the parameter. If it's a string, pass through unchanged
227             # If it's a datetime object, format it in ISO8601
228             # @param string $value the value of the parameter
229             # @return string the header string
230             sub to_string {
231 0     0 0   my ( $self, $value ) = @_;
232 0 0         if ( ref($value) eq "DateTime" ) { # datetime in ISO8601 format
233 0           return $value->datetime();
234             }
235             else {
236 0           return $value;
237             }
238             }
239              
240             # Deserialize a JSON string into an object
241             #
242             # @param string $class class name is passed as a string
243             # @param string $data data of the body
244             # @return object an instance of $class
245             sub deserialize {
246 0     0 0   my ( $self, $class, $data ) = @_;
247 0           $log->debugf( "deserializing %s for %s", $data, $class );
248              
249 0 0         if ( not defined $data ) {
    0          
    0          
    0          
    0          
250 0           return undef;
251             }
252             elsif ( ( substr( $class, 0, 5 ) ) eq 'HASH[' ) { #hash
253 0 0         if ( $class =~ /^HASH\[(.*),(.*)\]$/ ) {
254 0           my ( $key_type, $type ) = ( $1, $2 );
255 0           my %hash;
256 0           my $decoded_data = decode_json $data;
257 0           foreach my $key ( keys %$decoded_data ) {
258 0 0         if ( ref $decoded_data->{$key} eq 'HASH' ) {
259             $hash{$key} = $self->deserialize( $type,
260 0           encode_json $decoded_data->{$key} );
261             }
262             else {
263             $hash{$key} =
264 0           $self->deserialize( $type, $decoded_data->{$key} );
265             }
266             }
267 0           return \%hash;
268             }
269             else {
270             #TODO log error
271             }
272              
273             }
274             elsif ( ( substr( $class, 0, 6 ) ) eq 'ARRAY[' ) { # array of data
275 0 0         return $data if $data eq '[]'; # return if empty array
276              
277 0           my $_sub_class = substr( $class, 6, -1 );
278 0           my $_json_data = decode_json $data;
279 0           my @_values = ();
280 0           foreach my $_value (@$_json_data) {
281 0 0         if ( ref $_value eq 'ARRAY' ) {
282 0           push @_values,
283             $self->deserialize( $_sub_class, encode_json $_value);
284             }
285             else {
286 0           push @_values, $self->deserialize( $_sub_class, $_value );
287             }
288             }
289 0           return \@_values;
290             }
291             elsif ( $class eq 'DateTime' ) {
292 0           return DateTime->from_epoch( epoch => str2time($data) );
293             }
294             elsif ( grep /^$class$/, ( 'string', 'int', 'float', 'bool', 'object' ) ) {
295 0           return $data;
296             }
297             else { # model
298 0           my $_instance = use_module("Smartcat::Client::Object::$class")->new;
299 0 0         if ( ref $data eq "HASH" ) {
300 0           return $_instance->from_hash($data);
301             }
302             else { # string, need to json decode first
303 0           return $_instance->from_hash( decode_json $data);
304             }
305             }
306              
307             }
308              
309             # return 'Accept' based on an array of accept provided
310             # @param [Array] header_accept_array Array fo 'Accept'
311             # @return String Accept (e.g. application/json)
312             sub select_header_accept {
313 0     0 0   my ( $self, @header ) = @_;
314              
315 0 0 0       if ( @header == 0 || ( @header == 1 && $header[0] eq '' ) ) {
    0 0        
316 0           return undef;
317             }
318             elsif ( grep( /^application\/json$/i, @header ) ) {
319 0           return 'application/json';
320             }
321             else {
322 0           return join( ',', @header );
323             }
324              
325             }
326              
327             # return the content type based on an array of content-type provided
328             # @param [Array] content_type_array Array fo content-type
329             # @return String Content-Type (e.g. application/json)
330             sub select_header_content_type {
331 0     0 0   my ( $self, @header ) = @_;
332              
333 0 0 0       if ( @header == 0 || ( @header == 1 && $header[0] eq '' ) ) {
    0 0        
334 0           return 'application/json'; # default to application/json
335             }
336             elsif ( grep( /^application\/json$/i, @header ) ) {
337 0           return 'application/json';
338             }
339             else {
340 0           return join( ',', @header );
341             }
342              
343             }
344              
345             # Get API key (with prefix if set)
346             # @param string key name
347             # @return string API key with the prefix
348             sub get_api_key_with_prefix {
349 0     0 0   my ( $self, $key_name ) = @_;
350              
351 0           my $api_key = $self->{config}{api_key}{$key_name};
352              
353 0 0         return unless $api_key;
354              
355 0           my $prefix = $self->{config}{api_key_prefix}{$key_name};
356 0 0         return $prefix ? "$prefix $api_key" : $api_key;
357             }
358              
359             # update header and query param based on authentication setting
360             #
361             # @param array $headerParams header parameters (by ref)
362             # @param array $queryParams query parameters (by ref)
363             # @param array $authSettings array of authentication scheme (e.g ['api_key'])
364             sub update_params_for_auth {
365 0     0 0   my ( $self, $header_params, $query_params, $auth_settings ) = @_;
366              
367 0 0 0       return $self->_global_auth_setup( $header_params, $query_params )
368             unless $auth_settings && @$auth_settings;
369              
370             # one endpoint can have more than 1 auth settings
371 0           foreach my $auth (@$auth_settings) {
372              
373             # determine which one to use
374 0 0         if ( !defined($auth) ) {
375              
376             # TODO show warning about auth setting not defined
377             }
378             else {
379             # TODO show warning about security definition not found
380             }
381             }
382             }
383              
384             # The endpoint API class has not found any settings for auth. This may be deliberate,
385             # in which case update_params_for_auth() will be a no-op. But it may also be that the
386             # OpenAPI Spec does not describe the intended authorization. So we check in the config for any
387             # auth tokens and if we find any, we use them for all endpoints;
388             sub _global_auth_setup {
389 0     0     my ( $self, $header_params, $query_params ) = @_;
390              
391 0           my $tokens = $self->{config}->get_tokens;
392 0 0         return unless keys %$tokens;
393              
394             # basic
395 0 0         if ( my $uname = delete $tokens->{username} ) {
396 0           my $pword = delete $tokens->{password};
397 0           $header_params->{'Authorization'} =
398             'Basic ' . encode_base64( $uname . ":" . $pword );
399             }
400              
401             # oauth
402 0 0         if ( my $access_token = delete $tokens->{access_token} ) {
403 0           $header_params->{'Authorization'} = 'Bearer ' . $access_token;
404             }
405              
406             # other keys
407 0           foreach my $token_name ( keys %$tokens ) {
408 0           my $in = $tokens->{$token_name}->{in};
409 0           my $token = $self->get_api_key_with_prefix($token_name);
410 0 0         if ( $in eq 'head' ) {
    0          
411 0           $header_params->{$token_name} = $token;
412             }
413             elsif ( $in eq 'query' ) {
414 0           $query_params->{$token_name} = $token;
415             }
416             else {
417 0           die
418             "Don't know where to put token '$token_name' ('$in' is not 'head' or 'query')";
419             }
420             }
421             }
422              
423             1;