File Coverage

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