File Coverage

lib/eBay/API/Simple/Shopping.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             package eBay::API::Simple::Shopping;
2              
3 1     1   1130 use strict;
  1         2  
  1         27  
4 1     1   5 use warnings;
  1         2  
  1         31  
5              
6 1     1   5 use base 'eBay::API::SimpleBase';
  1         1  
  1         76  
7              
8             use HTTP::Request;
9             use HTTP::Headers;
10             use XML::Simple;
11             use utf8;
12              
13             our $DEBUG = 0;
14              
15             =head1 NAME
16              
17             eBay::API::Simple::Shopping - Support for eBay's Shopping web service
18              
19             =head1 DESCRIPTION
20              
21             This class provides support for eBay's Shopping web services.
22              
23             See http://developer.ebay.com/products/shopping/
24              
25             =head1 USAGE
26              
27             my $call = eBay::API::Simple::Shopping->new(
28             { appid => '' }
29             );
30             $call->execute( 'FindItemsAdvanced', { QueryKeywords => 'shoe' } );
31              
32             if ( $call->has_error() ) {
33             die "Call Failed:" . $call->errors_as_string();
34             }
35              
36             # getters for the response DOM or Hash
37             my $dom = $call->response_dom();
38             my $hash = $call->response_hash();
39              
40             print $call->nodeContent( 'Timestamp' );
41             print $call->nodeContent( 'TotalItems' );
42              
43             my @nodes = $dom->findnodes(
44             '/FindItemsAdvancedResponse/SearchResult/ItemArray/Item'
45             );
46              
47             foreach my $n ( @nodes ) {
48             print $n->findvalue('Title/text()') . "\n";
49             }
50              
51             =head1 SANDBOX USAGE
52              
53             my $call = eBay::API::Simple::Shopping->new( {
54             appid => '',
55             domain => 'open.api.sandbox.ebay.com',
56             } );
57            
58             $call->execute( 'FindItemsAdvanced', { QueryKeywords => 'shoe' } );
59              
60             if ( $call->has_error() ) {
61             die "Call Failed:" . $call->errors_as_string();
62             }
63              
64             # getters for the response DOM or Hash
65             my $dom = $call->response_dom();
66             my $hash = $call->response_hash();
67            
68             =head1 PUBLIC METHODS
69              
70             =head2 new( { %options } }
71              
72             Constructor for the Finding API call
73              
74             my $call = eBay::API::Simple::Shopping->new( {
75             appid => ''
76             ...
77             } );
78              
79             =head3 Options
80              
81             =over 4
82              
83             =item appid (required)
84              
85             This appid is required by the web service. App ids can be obtained at
86             http://developer.ebay.com
87              
88             =item siteid
89              
90             eBay site id to be supplied to the web service endpoint
91              
92             defaults to 0
93              
94             =item domain
95              
96             domain for the web service endpoint
97              
98             defaults to open.api.ebay.com
99              
100             =item uri
101              
102             endpoint URI
103              
104             defaults to /shopping
105              
106             =item version
107              
108             Version to be supplied to the web service endpoint
109              
110             defaults to 527
111              
112             =item https
113              
114             Specifies is the API calls should be made over https.
115              
116             defaults to 0
117              
118             =item enable_attributes
119              
120             This flag adds support for attributes in the request. If enabled request
121             data notes much be defined like so,
122              
123             myElement => { content => 'element content', myattr => 'attr value' }
124              
125             defaults to 0
126              
127             =back
128              
129             =head3 ALTERNATE CONFIG VIA ebay.yaml
130              
131             An ebay.yaml file can be used for configuring each
132             service endpoint.
133              
134             YAML files can be placed at the below locations. The first
135             file found will be loaded.
136              
137             ./ebay.yaml, ~/ebay.yaml, /etc/ebay.yaml
138              
139             Sample YAML:
140              
141             # Trading - External
142             api.ebay.com:
143             appid:
144             certid:
145             devid:
146             token:
147              
148             # Shopping
149             open.api.ebay.com:
150             appid:
151             certid:
152             devid:
153             version: 671
154              
155             # Finding/Merchandising
156             svcs.ebay.com:
157             appid:
158             version: 1.0.0
159              
160             =cut
161              
162             sub new {
163             my $class = shift;
164             my $self = $class->SUPER::new(@_);
165              
166             $self->api_config->{domain} ||= 'open.api.ebay.com';
167             $self->api_config->{uri} ||= '/shopping';
168              
169             $self->api_config->{version} ||= '527';
170             $self->api_config->{https} ||= 0;
171             $self->api_config->{siteid} ||= 0;
172             $self->api_config->{response_encoding} ||= 'XML'; # JSON, NV, SOAP
173             $self->api_config->{request_encoding} ||= 'XML';
174            
175             $self->_load_yaml_defaults();
176            
177             if ( $DEBUG ) {
178             print STDERR sprintf( "API CONFIG:\n%s\n",
179             $self->api_config_dump()
180             );
181             }
182              
183            
184             $self->_load_credentials();
185            
186             return $self;
187             }
188              
189             =head2 prepare( $verb, $call_data )
190              
191             $self->prepare( 'FindItemsAdvanced', { QueryKeywords => 'shoe' } );
192            
193             This method will construct the API request based on the $verb and
194             the $call_data.
195              
196             =item $verb (required)
197              
198             call verb, i.e. FindItemsAdvanced
199              
200             =item $call_data (required)
201              
202             hashref of call_data that will be turned into xml.
203              
204             =cut
205              
206             sub prepare {
207             my $self = shift;
208            
209             $self->{verb} = shift;
210             $self->{call_data} = shift;
211              
212             if ( ! defined $self->{verb} || ! defined $self->{call_data} ) {
213             die "missing verb and call_data";
214             }
215            
216             # make sure we have appid
217             $self->_load_credentials();
218             }
219              
220             =head1 BASECLASS METHODS
221              
222             =head2 request_agent
223              
224             Accessor for the LWP::UserAgent request agent
225              
226             =head2 request_object
227              
228             Accessor for the HTTP::Request request object
229              
230             =head2 request_content
231              
232             Accessor for the complete request body from the HTTP::Request object
233              
234             =head2 response_content
235              
236             Accessor for the HTTP response body content
237              
238             =head2 response_object
239              
240             Accessor for the HTTP::Request response object
241              
242             =head2 response_dom
243              
244             Accessor for the LibXML response DOM
245              
246             =head2 response_hash
247              
248             Accessor for the hashified response content
249              
250             =head2 nodeContent( $tag, [ $dom ] )
251              
252             Helper for LibXML that retrieves node content
253              
254             =head2 errors
255              
256             Accessor to the hashref of errors
257              
258             =head2 has_error
259              
260             Returns true if the call contains errors
261              
262             =head2 errors_as_string
263              
264             Returns a string of API errors if there are any.
265              
266             =head1 PRIVATE METHODS
267              
268             =head2 _get_request_body
269              
270             This method supplies the XML body for the web service request
271              
272             =cut
273              
274             sub _get_request_body {
275             my $self = shift;
276              
277             my $xml = ""
278             . "<" . $self->{verb} . "Request xmlns=\"urn:ebay:apis:eBLBaseComponents\">"
279             . XMLout(
280             $self->{call_data},
281             NoAttr => !$self->api_config->{enable_attributes},
282             KeepRoot => 1,
283             RootName => undef
284             )
285             . "{verb} . "Request>";
286              
287             return $xml;
288             }
289              
290             =head2 _get_request_headers
291              
292             This method supplies the HTTP::Headers obj for the web service request
293              
294             =cut
295              
296             sub _get_request_headers {
297             my $self = shift;
298            
299             my $obj = HTTP::Headers->new();
300              
301             $obj->push_header("X-EBAY-API-VERSION" => $self->api_config->{version});
302             $obj->push_header("X-EBAY-API-APP-ID" => $self->api_config->{appid});
303             $obj->push_header("X-EBAY-API-SITEID" => $self->api_config->{siteid});
304             $obj->push_header("X-EBAY-API-CALL-NAME" => $self->{verb});
305             $obj->push_header("X-EBAY-API-REQUEST-ENCODING" => $self->api_config->{request_encoding});
306             $obj->push_header("X-EBAY-API-RESPONSE-ENCODING" => $self->api_config->{response_encoding});
307             $obj->push_header("Content-Type" => "text/xml");
308            
309             return $obj;
310             }
311              
312             =head2 _get_request_object
313              
314             This method creates and returns the HTTP::Request object for the
315             web service call.
316              
317             =cut
318              
319             sub _get_request_object {
320             my $self = shift;
321              
322             my $url = sprintf( 'http%s://%s%s',
323             ( $self->api_config->{https} ? 's' : '' ),
324             $self->api_config->{domain},
325             $self->api_config->{uri}
326             );
327            
328             my $request_obj = HTTP::Request->new(
329             "POST",
330             $url,
331             $self->_get_request_headers,
332             $self->_get_request_body
333             );
334              
335             return $request_obj;
336             }
337              
338             sub _load_credentials {
339             my $self = shift;
340            
341             # we only need to load credentials once
342             return if $self->{_credentials_loaded};
343            
344             my @missing;
345            
346             # required by the API
347             for my $p ( qw/appid/ ) {
348             next if defined $self->api_config->{$p};
349            
350             if ( my $val = $self->_fish_ebay_ini( $p ) ) {
351             $self->api_config->{$p} = $val;
352             }
353             else {
354             push( @missing, $p );
355             }
356             }
357              
358             # die if we didn't get everything
359             if ( scalar @missing > 0 ) {
360             die "missing API credential: " . join( ", ", @missing );
361             }
362            
363             $self->{_credentials_loaded} = 1;
364             return;
365             }
366              
367             sub _fish_ebay_ini {
368             my $self = shift;
369             my $arg = shift;
370              
371             # initialize our hashref
372             $self->{_ebay_ini} ||= {};
373            
374             # revert eBay::API::Simple keys to standard keys
375             $arg = 'ApplicationKey' if $arg eq 'appid';
376              
377             # return it if we've already found it
378             return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
379            
380             # ini files in order of importance
381             my @files = (
382             './ebay.ini',
383             "$ENV{HOME}/ebay.ini",
384             '/etc/ebay.ini',
385             );
386            
387             foreach my $file ( reverse @files ) {
388             if ( open( FILE, "<", $file ) ) {
389            
390             while ( my $line = ) {
391             chomp( $line );
392            
393             next if $line =~ m!^\s*\#!;
394            
395             my( $k, $v ) = split( /=/, $line );
396            
397             if ( defined $k && defined $v) {
398             $v =~ s/^\s+//;
399             $v =~ s/\s+$//;
400            
401             $self->{_ebay_ini}{$k} = $v;
402             }
403             }
404              
405             close FILE;
406             }
407             }
408            
409             return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
410             return undef;
411             }
412              
413             1;
414              
415             =head1 AUTHOR
416              
417             Tim Keefer
418              
419             =cut