File Coverage

lib/WebService/TaxJar.pm
Criterion Covered Total %
statement 27 67 40.3
branch 0 6 0.0
condition n/a
subroutine 9 18 50.0
pod 4 4 100.0
total 40 95 42.1


line stmt bran cond sub pod time code
1 1     1   647 use strict;
  1         1  
  1         31  
2 1     1   4 use warnings;
  1         2  
  1         54  
3             package WebService::TaxJar;
4             $WebService::TaxJar::VERSION = '0.0001';
5 1     1   511 use HTTP::Thin;
  1         85070  
  1         42  
6 1     1   538 use HTTP::Request::Common qw/GET DELETE PUT POST/;
  1         3776  
  1         78  
7 1     1   569 use HTTP::CookieJar;
  1         28668  
  1         55  
8 1     1   731 use JSON;
  1         7896  
  1         6  
9 1     1   172 use URI;
  1         2  
  1         26  
10 1     1   488 use Ouch;
  1         1468  
  1         5  
11 1     1   591 use Moo;
  1         11131  
  1         7  
12              
13             =head1 NAME
14              
15             WebService::TaxJar - A simple client to L.
16              
17             =head1 VERSION
18              
19             version 0.0001
20              
21             =head1 SYNOPSIS
22              
23             use WebService::TaxJar;
24              
25             my $tj = WebService::TaxJar->new(api_key => 'XXXXXXXXXXxxxxxxxxxxxx', version => 'v2');
26              
27             my $categories = $tj->get('categories');
28              
29             =head1 DESCRIPTION
30              
31             A light-weight wrapper for TaxJar's RESTful API (an example of which can be found at: L). This wrapper basically hides the request cycle from you so that you can get down to the business of using the API. It doesn't attempt to manage the data structures or objects the web service interfaces with.
32              
33             The module takes care of all of these things for you:
34              
35             =over 4
36              
37             =item Host selection
38              
39             Based on the value of the C flag, the module will either send requests to the production environment C 0> or the sandbox environment C 1>.
40              
41             =item Adding authentication headers
42              
43             C adds an authentication header of the type "Authorization: Bearer C<$tj-Eapi_key>" to each request.
44              
45             =item Adding api version number to URLs
46              
47             C prepends the C< $tj-Eversion > to each URL you submit.
48              
49             =item PUT/POST data translated to JSON
50              
51             When making a request like:
52              
53             $tj->post('customers', { customer_id => '27', exemption_type => 'non_exempt', name => 'Andy Dufresne', });
54              
55             The data in POST request will be translated to JSON using .
56              
57             =item Response data is deserialized from JSON and returned from each call.
58              
59             =back
60              
61             =head1 EXCEPTIONS
62              
63             All exceptions in C are handled by C. A 500 exception C<"Server returned unparsable content."> is returned if TaxJar's server returns something that isn't JSON. If the request isn't successful, then an exception with the code and response and string will be thrown.
64              
65             =head1 METHODS
66              
67             The following methods are available.
68              
69             =head2 new ( params )
70              
71             Constructor.
72              
73             =over
74              
75             =item params
76              
77             A hash of parameters.
78              
79             =over
80              
81             =item api_key
82              
83             Your key for accessing TaxJar's API. Required.
84              
85             =item version
86              
87             The version of the API that you are using, like 'v1', 'v2', etc. Required.
88              
89             =item sandbox
90              
91             A boolean that, if true, will send all requests to TaxJar's sandbox environment for testing instead of to production. Defaults to 0.
92              
93             =cut
94              
95             =item debug_flag
96              
97             Just a spare, writable flag so that users of the object should log debug information, since TaxJar will likely ask for request/response pairs when
98             you're having problems.
99              
100             my $sales_tax = $taxjar->get('taxes', $order_information);
101             if ($taxjar->debug_flag) {
102             $log->info($taxjar->last_response->request->as_string);
103             $log->info($taxjar->last_response->content);
104             }
105              
106             =cut
107              
108             has api_key => (
109             is => 'ro',
110             required => 1,
111             );
112              
113             has version => (
114             is => 'ro',
115             required => 1,
116             );
117              
118             has sandbox => (
119             is => 'ro',
120             required => 0,
121             default => sub { 0 },
122             );
123              
124             has debug_flag => (
125             is => 'rw',
126             required => 0,
127             default => sub { 0 },
128             );
129              
130             =item agent
131              
132             A LWP::UserAgent compliant object used to keep a persistent cookie_jar across requests. By default this module uses HTTP::Thin, but you can supply another object when
133             creating a WebService::TaxJar object.
134              
135             =back
136              
137             =back
138              
139             =cut
140              
141             has agent => (
142             is => 'ro',
143             required => 0,
144             lazy => 1,
145             builder => '_build_agent',
146             );
147              
148             sub _build_agent {
149 0     0     return HTTP::Thin->new( cookie_jar => HTTP::CookieJar->new() )
150             }
151              
152             =head2 last_response
153              
154             The HTTP::Response object from the last request/reponse pair that was sent, for debugging purposes.
155              
156             =cut
157              
158             has last_response => (
159             is => 'rw',
160             required => 0,
161             );
162              
163             =head2 get(path, params)
164              
165             Performs a C request, which is used for reading data from the service.
166              
167             =over
168              
169             =item path
170              
171             The path to the REST interface you wish to call.
172              
173             =item params
174              
175             A hash reference of parameters you wish to pass to the web service. These parameters will be added as query parameters to the URL for you.
176              
177             =back
178              
179             =cut
180              
181             sub get {
182 0     0 1   my ($self, $path, $params) = @_;
183 0           my $uri = $self->_create_uri($path);
184 0           $uri->query_form($params);
185 0           return $self->_process_request( GET $uri->as_string );
186             }
187              
188             =head2 delete(path)
189              
190             Performs a C request, deleting data from the service.
191              
192             =over
193              
194             =item path
195              
196             The path to the REST interface you wish to call.
197              
198             =item params
199              
200             A hash reference of parameters you wish to pass to the web service. These parameters will be added as query parameters to the URL for you.
201              
202             =back
203              
204             =cut
205              
206             sub delete {
207 0     0 1   my ($self, $path, $params) = @_;
208 0           my $uri = $self->_create_uri($path);
209 0           $uri->query_form($params);
210 0           return $self->_process_request( DELETE $uri->as_string );
211             }
212              
213             =head2 put(path, json)
214              
215             Performs a C request, which is used for updating data in the service.
216              
217             =over
218              
219             =item path
220              
221             The path to the REST interface you wish to call.
222              
223             =item params
224              
225             A hash reference of parameters you wish to pass to Tax Jar. This will be translated to JSON.
226              
227             =back
228              
229             =cut
230              
231             sub put {
232 0     0 1   my ($self, $path, $params) = @_;
233 0           my $uri = $self->_create_uri($path);
234 0           my %headers = ( Content => to_json($params), "Content-Type" => 'application/json', );
235 0           return $self->_process_request( POST $uri->as_string, %headers );
236             }
237              
238             =head2 post(path, params, options)
239              
240             Performs a C request, which is used for creating data in the service.
241              
242             =over
243              
244             =item path
245              
246             The path to the REST interface you wish to call.
247              
248             =item params
249              
250             A hash reference of parameters you wish to pass to Tax Jar. They will be encoded as JSON.
251              
252             =back
253              
254             =head2 Notes
255              
256             The path you provide as arguments to the request methods C should not have a leading slash.
257              
258             As of early 2019:
259              
260             The current version of their API is 'v2'. There is no default value for the C parameter, so please provide this when creating a WebService::TaxJar object.
261              
262             TaxJar does not provide a free sandbox for prototyping your code, it is part of their premium service level.
263              
264             TaxJar's sandbox mode does not implement all API endpoints.
265              
266             =cut
267              
268             sub post {
269 0     0 1   my ($self, $path, $params) = @_;
270 0           my $uri = $self->_create_uri($path);
271 0           my %headers = ( Content => to_json($params), "Content-Type" => 'application/json', );
272 0           return $self->_process_request( POST $uri->as_string, %headers );
273             }
274              
275             sub _create_uri {
276 0     0     my $self = shift;
277 0           my $path = shift;
278 0 0         my $host = $self->sandbox
279             ? 'https://api.sandbox.taxjar.com'
280             : 'https://api.taxjar.com'
281             ;
282 0           return URI->new(join '/', $host, $self->version, $path);
283             }
284              
285             sub _add_auth_header {
286 0     0     my $self = shift;
287 0           my $request = shift;
288 0           $request->header( Authorization => 'Bearer '.$self->api_key() );
289 0           return;
290             }
291              
292             sub _process_request {
293 0     0     my $self = shift;
294 0           my $request = shift;
295 0           $self->_add_auth_header($request);
296 0           my $response = $self->agent->request($request);
297 0           $response->request($request);
298 0           $self->last_response($response);
299 0           $self->_process_response($response);
300             }
301              
302             sub _process_response {
303 0     0     my $self = shift;
304 0           my $response = shift;
305 0           my $result = eval { from_json($response->decoded_content) };
  0            
306 0 0         if ($@) {
    0          
307 0           ouch 500, 'Server returned unparsable content.', { error => $@, content => $response->decoded_content };
308             }
309             elsif ($response->is_success) {
310 0           return from_json($response->content);
311             }
312             else {
313 0           ouch $response->code, $response->as_string;
314             }
315             }
316              
317             =head1 PREREQS
318              
319             L
320             L
321             L
322             L
323             L
324             L
325             L
326              
327             =head1 SUPPORT
328              
329             =over
330              
331             =item Repository
332              
333             L
334              
335             =item Bug Reports
336              
337             L
338              
339             =back
340              
341             =head1 AUTHOR
342              
343             Colin Kuskie
344              
345             =head1 LEGAL
346              
347             This module is Copyright 2019 Plain Black Corporation. It is distributed under the same terms as Perl itself.
348              
349             =cut
350              
351             1;