File Coverage

lib/WebService/TaxJar.pm
Criterion Covered Total %
statement 27 73 36.9
branch 0 8 0.0
condition n/a
subroutine 9 19 47.3
pod 4 4 100.0
total 40 104 38.4


line stmt bran cond sub pod time code
1 1     1   542 use strict;
  1         2  
  1         24  
2 1     1   4 use warnings;
  1         1  
  1         45  
3             package WebService::TaxJar;
4             $WebService::TaxJar::VERSION = '0.0002';
5 1     1   388 use HTTP::Thin;
  1         68247  
  1         32  
6 1     1   412 use HTTP::Request::Common qw/GET DELETE PUT POST/;
  1         3203  
  1         58  
7 1     1   432 use HTTP::CookieJar;
  1         26894  
  1         48  
8 1     1   611 use JSON;
  1         6800  
  1         5  
9 1     1   121 use URI;
  1         1  
  1         18  
10 1     1   424 use Ouch;
  1         1246  
  1         4  
11 1     1   536 use Moo;
  1         9373  
  1         4  
12              
13             =head1 NAME
14              
15             WebService::TaxJar - A simple client to L.
16              
17             =head1 VERSION
18              
19             version 0.0002
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. Optional, defaults to 'v2'.
88              
89             =item api_version
90              
91             Tax Jar decided to move away from a numbered scheme where the version is in the URL to a date based version in the HTTP headers. This flag is optional, and defaults
92             to '2022-01-24', which is the default date as of May 2022. The date must be in the version of 'YYYY-MM-DD' to be accepted by TaxJar, but this module will not validate
93             your date flag.
94              
95             =item sandbox
96              
97             A boolean that, if true, will send all requests to TaxJar's sandbox environment for testing instead of to production. Defaults to 0.
98              
99             =cut
100              
101             =item debug_flag
102              
103             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
104             you're having problems.
105              
106             my $sales_tax = $taxjar->get('taxes', $order_information);
107             if ($taxjar->debug_flag) {
108             $log->info($taxjar->last_response->request->as_string);
109             $log->info($taxjar->last_response->content);
110             }
111              
112             =cut
113              
114             has api_key => (
115             is => 'ro',
116             required => 1,
117             );
118              
119             has version => (
120             is => 'ro',
121             required => 0,
122             default => sub { 'v2' },
123             );
124              
125             has api_version => (
126             is => 'ro',
127             required => 0,
128             default => sub { '2022-01-24' },
129             );
130              
131             has sandbox => (
132             is => 'ro',
133             required => 0,
134             default => sub { 0 },
135             );
136              
137             has debug_flag => (
138             is => 'rw',
139             required => 0,
140             default => sub { 0 },
141             );
142              
143             =item agent
144              
145             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
146             creating a WebService::TaxJar object.
147              
148             =back
149              
150             =back
151              
152             =cut
153              
154             has agent => (
155             is => 'ro',
156             required => 0,
157             lazy => 1,
158             builder => '_build_agent',
159             );
160              
161             sub _build_agent {
162 0     0     return HTTP::Thin->new( cookie_jar => HTTP::CookieJar->new() )
163             }
164              
165             =head2 last_response
166              
167             The HTTP::Response object from the last request/reponse pair that was sent, for debugging purposes.
168              
169             =cut
170              
171             has last_response => (
172             is => 'rw',
173             required => 0,
174             );
175              
176             =head2 get(path, params)
177              
178             Performs a C request, which is used for reading data from the service.
179              
180             =over
181              
182             =item path
183              
184             The path to the REST interface you wish to call.
185              
186             =item params
187              
188             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.
189              
190             =back
191              
192             =cut
193              
194             sub get {
195 0     0 1   my ($self, $path, $params) = @_;
196 0           my $uri = $self->_create_uri($path);
197 0           $uri->query_form($params);
198 0           return $self->_process_request( GET $uri->as_string );
199             }
200              
201             =head2 delete(path)
202              
203             Performs a C request, deleting data from the service.
204              
205             =over
206              
207             =item path
208              
209             The path to the REST interface you wish to call.
210              
211             =item params
212              
213             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.
214              
215             =back
216              
217             =cut
218              
219             sub delete {
220 0     0 1   my ($self, $path, $params) = @_;
221 0           my $uri = $self->_create_uri($path);
222 0           $uri->query_form($params);
223 0           return $self->_process_request( DELETE $uri->as_string );
224             }
225              
226             =head2 put(path, json)
227              
228             Performs a C request, which is used for updating data in the service.
229              
230             =over
231              
232             =item path
233              
234             The path to the REST interface you wish to call.
235              
236             =item params
237              
238             A hash reference of parameters you wish to pass to Tax Jar. This will be translated to JSON.
239              
240             =back
241              
242             =cut
243              
244             sub put {
245 0     0 1   my ($self, $path, $params) = @_;
246 0           my $uri = $self->_create_uri($path);
247 0           my %headers = ( Content => to_json($params), "Content-Type" => 'application/json', );
248 0           return $self->_process_request( POST $uri->as_string, %headers );
249             }
250              
251             =head2 post(path, params, options)
252              
253             Performs a C request, which is used for creating data in the service.
254              
255             =over
256              
257             =item path
258              
259             The path to the REST interface you wish to call.
260              
261             =item params
262              
263             A hash reference of parameters you wish to pass to Tax Jar. They will be encoded as JSON.
264              
265             =back
266              
267             =head2 Notes
268              
269             The path you provide as arguments to the request methods C should not have a leading slash.
270              
271             As of early 2019:
272              
273             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.
274              
275             TaxJar does not provide a free sandbox for prototyping your code, it is part of their premium service level.
276              
277             TaxJar's sandbox mode does not implement all API endpoints.
278              
279             =cut
280              
281             sub post {
282 0     0 1   my ($self, $path, $params) = @_;
283 0           my $uri = $self->_create_uri($path);
284 0           my %headers = ( Content => to_json($params), "Content-Type" => 'application/json', );
285 0           return $self->_process_request( POST $uri->as_string, %headers );
286             }
287              
288             sub _create_uri {
289 0     0     my $self = shift;
290 0           my $path = shift;
291 0 0         my $host = $self->sandbox
292             ? 'https://api.sandbox.taxjar.com'
293             : 'https://api.taxjar.com'
294             ;
295 0           return URI->new(join '/', $host, $self->version, $path);
296             }
297              
298             sub _add_auth_header {
299 0     0     my $self = shift;
300 0           my $request = shift;
301 0           $request->header( Authorization => 'Bearer '.$self->api_key() );
302 0           return;
303             }
304              
305             sub _add_version_header {
306 0     0     my $self = shift;
307 0           my $request = shift;
308 0 0         if ($self->api_version) {
309 0           $request->header( 'x-api-version' => $self->api_version() );
310             }
311 0           return;
312             }
313              
314             sub _process_request {
315 0     0     my $self = shift;
316 0           my $request = shift;
317 0           $self->_add_auth_header($request);
318 0           $self->_add_version_header($request);
319 0           my $response = $self->agent->request($request);
320 0           $response->request($request);
321 0           $self->last_response($response);
322 0           $self->_process_response($response);
323             }
324              
325             sub _process_response {
326 0     0     my $self = shift;
327 0           my $response = shift;
328 0           my $result = eval { from_json($response->decoded_content) };
  0            
329 0 0         if ($@) {
    0          
330 0           ouch 500, 'Server returned unparsable content.', { error => $@, content => $response->decoded_content };
331             }
332             elsif ($response->is_success) {
333 0           return from_json($response->content);
334             }
335             else {
336 0           ouch $response->code, $response->as_string;
337             }
338             }
339              
340             =head1 PREREQS
341              
342             L
343             L
344             L
345             L
346             L
347             L
348             L
349              
350             =head1 SUPPORT
351              
352             =over
353              
354             =item Repository
355              
356             L
357              
358             =item Bug Reports
359              
360             L
361              
362             =back
363              
364             =head1 AUTHOR
365              
366             Colin Kuskie
367              
368             =head1 LEGAL
369              
370             This module is Copyright 2019 Plain Black Corporation. It is distributed under the same terms as Perl itself.
371              
372             =cut
373              
374             1;