File Coverage

blib/lib/Net/MyCommerce/API/Client.pm
Criterion Covered Total %
statement 80 95 84.2
branch 15 32 46.8
condition 12 27 44.4
subroutine 17 18 94.4
pod 2 2 100.0
total 126 174 72.4


line stmt bran cond sub pod time code
1             # Copyright 2013 Digital River, Inc.
2             #
3             # Licensed under the Apache License, Version 2.0 (the "License");
4             # you may not use this file except in compliance with the License.
5             # You may obtain a copy of the License at
6             #
7             # http://www.apache.org/licenses/LICENSE-2.0
8             #
9             # Unless required by applicable law or agreed to in writing, software
10             # distributed under the License is distributed on an "AS IS" BASIS,
11             # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12             # See the License for the specific language governing permissions and
13             # limitations under the License.
14              
15             package Net::MyCommerce::API::Client;
16              
17 3     3   15 use strict;
  3         6  
  3         97  
18 3     3   15 use warnings;
  3         6  
  3         71  
19              
20 3     3   2775 use Encode qw( decode_utf8 );
  3         55383  
  3         310  
21 3     3   2365 use JSON::Parse qw( json_to_perl );
  3         2759  
  3         209  
22 3     3   3924 use JSON::XS;
  3         475976  
  3         278  
23 3     3   4020 use MIME::Base64;
  3         13013  
  3         299  
24 3     3   5692 use REST::Client;
  3         7802454  
  3         123  
25 3     3   2737 use Try::Tiny;
  3         4529  
  3         292  
26 3     3   21 use URI::Escape qw( uri_escape );
  3         16  
  3         3363  
27              
28             =head1 NAME
29            
30             Net::MyCommerce::API::Client
31            
32             =head1 VERSION
33            
34             version 1.0.1
35            
36             =cut
37            
38             our $VERSION = '1.0.1';
39            
40             =head1 METHODS
41              
42             =head2 new
43              
44             REST::Client wrapper used by Net::MyCommerce::API::Token and Net::MyCommerce::API::Resource
45              
46             =cut
47              
48             sub new {
49 3     3 1 56 my ($pkg, %args) = @_;
50 3         56 $args{client} = REST::Client->new(%args);
51 3   100     13757 $args{timeout} ||= 60;
52 3         43 return bless { %args }, $pkg;
53             }
54              
55             =head2 request (%opts)
56              
57             %opns:
58              
59             path: (required) full path or array ref with path elements; exclude prefix
60             params: (optional) query params
61             headers: (optional) headers
62              
63              
64             my $client = Net::MyCommerce::API::Client->new(%args);
65             my ($error, $result) = $client->request(%opts);
66             my $content = $result->{content};
67             my $status_code = $result->{status_code};
68             my $headers = $result->{headers};
69              
70             =cut
71              
72             sub request {
73 2     2 1 24 my ($self, %opts) = @_;
74 2         17 $self->{client}->request($self->_parse_options(%opts));
75 2         3405840 return $self->_parse_response($self->{client}->{_res});
76             }
77              
78             # Private Methods
79              
80             sub _parse_path {
81 2     2   7 my ($self, %opts) = @_;
82 2   50     24 my $prefix = $opts{prefix} || $self->{prefix} || '';
83 2   33     23 my $path = $opts{path} || $self->{path};
84 2   50     16 my $params = $opts{params} || $self->{params} || {};
85 2 50       13 if (ref($path) eq 'ARRAY') {
86 0         0 my $newpath = join("/", @$path);
87 0         0 $path = $newpath;
88             }
89 2 50       10 if (keys %$params > 0) {
90 0         0 my @list = ();
91 0         0 foreach my $n (sort keys %$params) {
92 0         0 push @list, join("=", $n, uri_escape($params->{$n}));
93             }
94 0         0 $path .= '?' . join("&", @list);
95             }
96 2         7 $opts{path} = $prefix . $path;
97 2         11 return %opts;
98             }
99              
100             sub _parse_data {
101 2     2   5 my ($self, %opts) = @_;
102 2 50       24 if ($opts{method} =~ /^(POST|PUT)$/) {
103 2 50       8 $opts{data} = encode_json($opts{data}) if $self->{sendJSON};
104             } else {
105 0         0 $opts{data} = '';
106             }
107 2         14 return %opts;
108             }
109              
110             sub _parse_headers {
111 2     2   7 my ($self, %opts) = @_;
112 2   50     29 my $headers = $opts{headers} || $self->{headers} || {};
113 2 50 33     26 if ($self->{credentials}{id} &&
    50          
114             $self->{credentials}{secret}) {
115 0         0 my $auth = join(":", $self->{credentials}{id}, $self->{credentials}{secret});
116 0         0 chomp( $headers->{Authorization} = 'Basic ' . encode_base64($auth) );
117             } elsif ($opts{token_id}) {
118 0         0 $headers->{Authorization} = 'Bearer ' . $opts{token_id};
119             }
120 2 50       21 if ($opts{method} =~ /^(POST|PUT)$/) {
121 2 50       8 if ($self->{sendJSON}) {
122 0         0 $headers->{'Content-type'} = 'application/json;charset=UTF-8';
123             } else {
124 2         6 $headers->{'Content-type'} = 'application/x-www-form-urlencoded';
125             }
126             }
127 2         5 $opts{headers} = $headers;
128 2         14 return %opts;
129             }
130              
131             sub _parse_options {
132 2     2   6 my ($self, %opts) = @_;
133 2   50     25 $opts{method} ||= $self->{method} || 'GET';
      33        
134 2         10 %opts = $self->_parse_path(%opts);
135 2         12 %opts = $self->_parse_data(%opts);
136 2         15 %opts = $self->_parse_headers(%opts);
137 2         19 return ($opts{method}, $opts{path}, $opts{data}, $opts{headers});
138             }
139              
140             sub _parse_response {
141 2     2   6 my ($self, $response) = @_;
142 2 50       16 if ($response) {
143 2         6 my $error = '';
144 2         7 my $result = {};
145 2         24 my $content = $response->content;
146             try {
147 2 50   2   207 if ($content) {
148 2         22 $content = decode_utf8($content);
149 2 50       207 $content = json_to_perl($content) if $self->{getJSON};
150             } else {
151 0 0       0 $content = {} if $self->{getJSON};
152             }
153             } catch {
154 0     0   0 $content =~ s/\s+/ /g;;
155 0         0 $error = $_ . " [" . $content . "]";
156 2         61 };
157 2 50       131 if (ref($content) eq 'HASH') {
158 2   50     14 my $errmsg = $content->{error} || '';
159 2 50       11 $errmsg .= ": " . $content->{error_code} if $content->{error_code};
160 2 50       17 $errmsg .= ": " . $content->{error_description} if $content->{error_description};
161 2   33     24 $error ||= $errmsg;
162             }
163 2 50       16 if ($response->code =~ /^[345]/) {
164 2   33     43 $error ||= "status code " . $response->code;
165             }
166 2         6 $result->{content} = $content;
167 2         11 $result->{status_code} = $response->code;
168 2         30 $result->{headers} = $response->headers;
169 2         29 return ($error, $result);
170             }
171 0           return ("no response", {});
172             }
173              
174              
175             1;