view release on metacpan or search on metacpan
# Changes for eBay::API::Simple
TODO: add ClientAlerts and BestMatch backend
0.29 Wed Aug 1 17:34:01 PDT 2012
- add IAF Token support to Trading module
0.28 Mon May 7 16:37:35 PDT 2012
- add allow_blessed and convert_blessed to json encode call
0.27
- add support for basic authorization
0.25
- add support for parallel requests using LWP::Parallel
0.24
- fix HTML and RSS test scripts (stale URLs)
- in build_urls method, use sort for consistent URL output
- add better error handling for JSON backend
0.23 Fri May 27 17:31:16 PDT 2011
- add JSON backend
0.22 Fri Apr 1 10:16:30 PDT 2011
- rework test scripts
0.21 Thu Jan 27 22:08:31 PST 2011
- build url function now allows for multiple keys in the query string
i.e. /uri/?q=foo1&q=foo2&q=foo3
- fix prereq - dependent on URI::Encode >= 3.30
0.20 Wed Jan 26 21:23:35 PST 2011
- fix test
0.19 Wed Jan 26 13:35:59 PST 2011
- check for $ENV{HOME} being defined before using
- add more utf8 fixes
- add special fix for unicode in 5.8.1
0.18 Wed Jul 28 13:11:30 GMT+7 2010
- encode "keywords" field for UTF-8 in Finding module
- test for UTF-8 compatibility for Finding module
0.17 Thu Jul 15 14:09:57 PDT 2010
- add YAML support for API configurations
- remove worldofgood test
- add SellerReport.pl script for pulling out the sellers details from
Shopping and Trading api and the usage of ebay.yaml
0.16 Thu Jul 1 15:00:46 PDT 2010
- add support for attributes in the request via enable_attributes flag
0.15 Tue Jun 15 15:00:55 PDT 2010
- add sandbox docs
- modify Finding backend to support the "X-EBAY-SOA-SERVICE-NAME"
defaults to: FindingService
* provides support custom services on the Finding platform
0.14
- modify debugging
- modify Trading backend: calls can now be made without a password
since it's not required for a fetch token call.
0.13 Fri Feb 5 13:28:31 PST 2010
- add query string arg support for RSS and HTML backends
- fixed XML namespace stripping (now done in base class with optional override)
0.12 Wed Jan 27 11:32:30 PST 2010
- add support to the Merchandising services
0.11 Tue Jan 26 18:15:38 PST 2010
- add to documentation
0.10 Sat Jan 23 19:44:31 PST 2010
- fix tests
0.09 Fri Jan 22 11:54:36 PST 2010
- fix version issue
0.07 Fri Jan 22 11:34:36 PST 2010
- add support for eBay Finding2.0 services
* eBay::API::Simple::Finding
- add proxy support to base class
0.06 Mon Aug 3 09:06:58 PDT 2009
- fix fish config routine
- add Simple.pm subclass
0.05 Mon Jul 20 17:30:43 PDT 2009
- add default timeout of 20 seconds
- added support for username/password on Trading API
0.04 Mon Feb 16 15:40:05 PST 2009
- release to CPAN
- code cleanup
- add ebay.ini support
- fix tests
- fix xmlout bug in Shopping backend
0.02 Thu Jan 8 13:34:36 PST 2009
- several doc udpates
- made some cosmetic changes
0.01 Thu Jan 8 10:03:09 PST 2009
- alpha release for this eBay::API::Simple library
Changes
lib/eBay/API/Simple.pm
lib/eBay/API/Simple/Finding.pm
lib/eBay/API/Simple/HTML.pm
lib/eBay/API/Simple/JSON.pm
lib/eBay/API/Simple/Merchandising.pm
lib/eBay/API/Simple/Parallel.pm
lib/eBay/API/Simple/RSS.pm
lib/eBay/API/Simple/Shopping.pm
lib/eBay/API/Simple/Trading.pm
lib/eBay/API/SimpleBase.pm
docs/ebay.yaml
Makefile.PL
MANIFEST This list of files
README.rst
t/01use.t
ex/01Shopping.t
ex/02HTML.t
ex/03Trading.t
ex/04RSS.t
ex/05Finding.t
ex/05Finding_utf8.t
ex/06Merchandising.t
ex/09HalfShopping.t
META.yml Module YAML meta-data (added by MakeMaker)
META.json Module JSON meta-data (added by MakeMaker)
{
"abstract" : "Flexible SDK supporting all eBay web services",
"author" : [
"Tim Keefer <tkeefer@gmail.com>"
],
"dynamic_config" : 1,
"generated_by" : "ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112150",
"license" : [
"unknown"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : "2"
},
"name" : "eBay-API-Simple",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : 0
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : 0
}
},
"runtime" : {
"requires" : {
"HTTP::Headers" : 0,
"HTTP::Request" : 0,
"JSON" : 0,
"LWP::UserAgent" : 0,
"URI" : "1.57",
"URI::Escape" : 0,
"XML::LibXML" : 0,
"XML::Parser" : 0,
"XML::Simple" : 0,
"YAML" : 0
}
}
},
"release_status" : "stable",
"version" : "0.29"
}
---
abstract: 'Flexible SDK supporting all eBay web services'
author:
- 'Tim Keefer <tkeefer@gmail.com>'
build_requires:
ExtUtils::MakeMaker: 0
configure_requires:
ExtUtils::MakeMaker: 0
dynamic_config: 1
generated_by: 'ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112150'
license: unknown
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: 1.4
name: eBay-API-Simple
no_index:
directory:
- t
- inc
requires:
HTTP::Headers: 0
HTTP::Request: 0
JSON: 0
LWP::UserAgent: 0
URI: 1.57
URI::Escape: 0
XML::LibXML: 0
XML::Parser: 0
XML::Simple: 0
YAML: 0
version: 0.29
Makefile.PL view on Meta::CPAN
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
NAME => 'eBay::API::Simple',
VERSION_FROM => 'lib/eBay/API/Simple.pm',
PREREQ_PM => {
'XML::LibXML' => 0,
'HTTP::Headers' => 0,
'HTTP::Request' => 0,
'LWP::UserAgent' => 0,
'XML::Parser' => 0,
'XML::Simple' => 0,
'URI' => 1.57,
'URI::Escape' => 0,
'YAML' => 0,
'JSON' => 0,
}, # e.g., Module::Name => 1.1
($] >= 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'lib/eBay/API/Simple.pm', #abstract from module
AUTHOR => 'Tim Keefer <tkeefer@gmail.com>') : ()),
);
eBay::API::Simple
===========================
This module supports eBay's Shopping and Trading API services. In addition, eBay::API::Simple comes with a standard RSS and HTML back-end.
In order to use eBay aspects of this utility you must first register with eBay to get your `eBay Develoepr Site`_ API developer credentials] (see the ebay.yaml option for a way to tie these credentials into the Shopping and Trading back-ends)
Parallel Requests::
my $pua = eBay::API::Simple::Parallel->new();
my $call1 = eBay::API::Simple::RSS->new( {
parallel => $pua,
} );
$call1->execute(
âhttp://worldofgood.ebay.com/Clothes-Shoes-Men/43/list?format=rssâ,
);
my $call2 = eBay::API::Simple::RSS->new( {
parallel => $pua,
} );
$call2->execute(
âhttp://worldofgood.ebay.com/Home-Garden/46/list?format=rssâ
);
$pua->wait();
if ( $pua->has_error() ) {
print "ONE OR MORE FAILURES!\n";
}
print $call1->response_content() . "\n";
print $call2->response_content() "\n";
Merchandising Services::
use eBay::API::Simple::Merchandising;
my $api = eBay::API::Simple::Merchandising->new( {
appid => '<your app id here>',
} );
$api->execute( 'getMostWatchedItems', {
maxResults => 3, categoryId => 267
});
if ( $api->has_error() ) {
die "Call Failed:" . $api->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $api->response_dom();
my $hash = $api->response_hash();
[eBayAPISimpleMerchandising#Sandbox_Usage Sandbox Usage] |
[eBayAPISimpleMerchandising#Module_Documentation Module Documentation]
Finding Services::
use eBay::API::Simple::Finding;
my $api = eBay::API::Simple::Finding->new( {
appid => 'myappid',
} );
$api->execute( 'findItemsByKeywords', { keywords => 'shoe' } );
if ( $api->has_error() ) {
die "Call Failed:" . $api->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $api->response_dom();
my $hash = $api->response_hash();
[eBayAPISimpleFinding#Sandbox_Usage Sandbox Usage] |
[eBayAPISimpleFinding#Module_Documentation Module Documentation]
Shopping Services::
use eBay::API::Simple::Shopping;
my $api = eBay::API::Simple::Shopping->new( {
appid => 'myappid',
} );
$api->execute( 'FindItemsAdvanced', { QueryKeywords => 'shoe' } );
if ( $api->has_error() ) {
die "Call Failed:" . $api->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $api->response_dom();
my $hash = $api->response_hash();
[eBayAPISimpleShopping#Sandbox_Usage Sandbox Usage] |
[eBayAPISimpleShopping#Module_Documentation Module Documentation]
Trading Services::
use eBay::API::Simple::Trading;
my $api = eBay::API::Simple::Trading->new( {
appid => 'myappid',
devid => 'mydevid',
certid => 'mycertid',
token => $mytoken,
} );
$api->execute( 'GetSearchResults', { Query => 'shoe' } );
if ( $api->has_error() ) {
die "Call Failed:" . $api->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $api->response_dom();
my $hash = $api->response_hash();
[eBayAPISimpleTrading#Sandbox_Usage Sandbox Usage] |
[eBayAPISimpleTrading#Module_Documentation Module Documentation]
Generic JSON Backend::
use eBay::API::Simple::JSON;
my $api = eBay::API::Simple::JSON->new();
# 'GET' call
$api->get(
'http://localhost-django-vm.ebay.com/green/api/v1/greenerAlternative/32/'
);
if ( $api->has_error() ) {
die "Call Failed:" . $api->errors_as_string();
}
# convenience methods
my $hash = $api->response_hash();
my $response_content = $api->response_content();
my $request_content = $api->request_content();
# HTTP::Request
print $api->request->as_string();
# HTTP::Response
print $api->response->as_string();
print $api->response->content();
print $api->response->is_error();
# HTTP::Headers
print $api->response->headers->as_string();
print $api->response->headers->content_type();
# 'POST', 'PUT', 'DELETE' calls
my $data = {
"user_eais_token" => "tim",
"body_text" => "mytext"
};
$api->post( 'http://myendpoint', $data );
$api->put( 'http://myendpoint', $data );
$api->delete( 'http://myendpoint' );
Generic HTML Backend::
use eBay::API::Simple::HTML;
my $api = eBay::API::Simple::HTML->new();
$api->execute( 'http://www.example.com' );
if ( $api->has_error() ) {
die "Call Failed:" . $api->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $api->response_dom();
my $hash = $api->response_hash();
Generic RSS Backend::
use eBay::API::Simple::RSS;
my $api = eBay::API::Simple::RSS->new();
$api->execute(
'http://sfbay.craigslist.org/search/sss?query=shirt&format=rss'
);
if ( $api->has_error() ) {
die "Call Failed:" . $api->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $api->response_dom();
my $hash = $api->response_hash();
More Docs::
Visit CPAN to view the full documentation for [http://search.cpan.org/search?query=eBay%3A%3AAPI%3A%3ASimple eBay::API::Simple].
.. _eBay Developer Site: http://developer.ebay.com/
docs/ebay.yaml view on Meta::CPAN
# eBay::API::Simple API Configurations
name: ebay_api_config
# Trading - External
api.ebay.com:
password: pass
username: user
appid: appid
certid: certid
devid: devid
token: token
# Shopping
open.api.ebay.com:
appid: appid
certid: certid
devid: devid
version: 671
# Finding/Merchandising
svcs.ebay.com:
appid: appid
version: 1.0.0
ex/01Shopping.t view on Meta::CPAN
use Test::More;
use strict; no warnings;
#use LWP::Debug qw(+);
use Data::Dumper;
use lib qw/lib/;
my @skip_msg;
BEGIN {
eval {
use eBay::API::Simple::Shopping;
};
if ( $@ ) {
push @skip_msg, 'missing module eBay::API::Simple::Shopping, skipping test';
}
if ( scalar( @skip_msg ) ) {
plan skip_all => join( ' ', @skip_msg );
}
else {
plan qw(no_plan);
}
}
my $call;
eval {
$call = eBay::API::Simple::Shopping->new(
{ appid => undef } # <----- your appid here
);
};
if ( $@ ) {
push( @skip_msg, $@ );
}
#$call->api_init( {
# site_id => 0,
# uri => $arg_uri,
# domain => $arg_domain,
# app_id => $arg_appid,
# version => $arg_version,
#} );
eval {
};
SKIP: {
skip join( ' ', @skip_msg), 1 if scalar( @skip_msg );
$call->execute( 'FindItemsAdvanced', {
QueryKeywords => 'black shoes',
MaxEntries => 5,
} );
#diag $call->request_content;
#diag $call->response_content;
if ( $call->has_error() ) {
fail( 'api call failed: ' . $call->errors_as_string() );
}
else {
is( ref $call->response_dom(), 'XML::LibXML::Document', 'response dom' );
is( ref $call->response_hash(), 'HASH', 'response hash' );
like( $call->nodeContent('Timestamp'),
qr/^\d{4}-\d{2}-\d{2}/,
'response timestamp'
);
ok( $call->nodeContent('TotalItems') > 10, 'response total items' );
#diag( 'total items: ' . $call->nodeContent('TotalItems') );
#diag( Dumper( $call->response_hash() ) );
}
$call->execute( 'BadCall', { QueryKeywords => 'shoe' } );
is( $call->has_error(), 1, 'look for error flag' );
ok( $call->errors_as_string() ne '', 'check for error message' );
ok( $call->response_content() ne '', 'check for response content' );
$call->execute( 'FindItemsAdvanced', { QueryKeywords => 'shoe' } );
is( $call->has_error(), 0, 'error check' );
is( $call->errors_as_string(), '', 'error string check' );
ok( $call->nodeContent('TotalItems') > 10, 'response total items' );
#diag( Dumper( $call->response_content() ) );
my @nodes = $call->response_dom->findnodes(
'/FindItemsAdvancedResponse/SearchResult/ItemArray/Item'
);
foreach my $n ( @nodes ) {
# diag( $n->findvalue('Title/text()') );
ok( $n->findvalue('Title/text()') ne '', 'title check' );
}
my $call2 = eBay::API::Simple::Shopping->new( { response_encoding => 'XML' } );
$call2->execute( 'FindPopularSearches', { QueryKeywords => 'shoe' } );
#diag( $call2->response_content() );
}
ex/02HTML.t view on Meta::CPAN
use Test::More;
use strict; no warnings;
#use LWP::Debug qw(+);
use Data::Dumper;
use lib qw/lib/;
BEGIN {
my @skip_msg;
eval {
use eBay::API::Simple::HTML;
};
if ( $@ ) {
push @skip_msg, 'missing module eBay::API::Simple::HTML, skipping test';
}
if ( scalar( @skip_msg ) ) {
plan skip_all => join( ' ', @skip_msg );
}
else {
plan qw(no_plan);
}
}
my $call = eBay::API::Simple::HTML->new();
$call->execute( 'http://www.example.com/', { utm_campaign =>'simple_test' } );
#diag $call->request_content();
#diag $call->response_content();
if ( $call->has_error() ) {
fail( 'api call failed: ' . $call->errors_as_string() );
}
else {
is( ref $call->response_dom(), 'XML::LibXML::Document', 'response dom' );
is( ref $call->response_hash(), 'HASH', 'response hash' );
like( $call->response_hash->{head}{title},
qr/Example/i,
'hash test'
);
ok( $call->nodeContent('title') =~ /example/i,
'nodeContent test' );
#diag Dumper( $call->response_hash );
}
$call->execute( 'http://bogusurlexample.com' );
is( $call->has_error(), 1, 'look for error flag' );
ok( $call->errors_as_string() ne '', 'check for error message' );
ok( $call->response_content() ne '', 'check for response content' );
ex/03Trading.t view on Meta::CPAN
use Test::More;
use strict; no warnings;
#use LWP::Debug qw(+);
use Data::Dumper;
use lib qw/lib/;
BEGIN {
my @skip_msg;
eval {
use eBay::API::Simple::Trading;
};
if ( $@ ) {
push @skip_msg, 'missing module eBay::API::Simple::Trading, skipping test';
}
if ( scalar( @skip_msg ) ) {
plan skip_all => join( ' ', @skip_msg );
}
else {
plan qw(no_plan);
}
}
my $call = eBay::API::Simple::Trading->new( {
# domain => 'internal-api.vip.ebay.com',
} );
#$call->api_init( {
# site_id => 0,
# uri => $arg_uri,
# domain => $arg_domain,
# app_id => $arg_appid,
# version => $arg_version,
#} );
eval{
$call->execute( 'GetCategories',
{ DetailLevel => 'ReturnAll',
LevelLimit => 2,
CategoryParent => 11116,
}
);
};
SKIP: {
skip $@, 1 if $@;
if ( $call->has_error() ) {
fail( 'api call failed: ' . $call->errors_as_string() );
}
else {
is( ref $call->response_dom(), 'XML::LibXML::Document', 'response dom' );
is( ref $call->response_hash(), 'HASH', 'response hash' );
like( $call->nodeContent('Timestamp'),
qr/^\d{4}-\d{2}-\d{2}/,
'response timestamp'
);
ok( $call->nodeContent('ReduceReserveAllowed') =~ /(true|false)/,
'reduce reserve allowed node' );
}
}
$call->execute( 'BadCallSSS', { Query => 'shoe' } );
is( $call->has_error(), 1, 'look for error flag' );
ok( $call->errors_as_string() eq 'Call Failure-The API call "BadCallSSS" is invalid or not supported in this release.', 'check for error message' );
ok( $call->response_content() ne '', 'check for response content' );
$call->execute( 'GetSearchResults', { Query => 'shoe', Pagination => { EntriesPerPage => 2, PageNumber => 1 } } );
is( $call->has_error(), 0, 'error check' );
is( $call->errors_as_string(), '', 'error string check' );
ok( $call->nodeContent('TotalNumberOfEntries') > 10, 'response total items' );
#diag $call->request_object->as_string();
my @nodes = $call->response_dom->findnodes(
'//Item'
);
foreach my $n ( @nodes ) {
#diag( $n->findvalue('Title/text()') );
ok( $n->findvalue('Title/text()') ne '', 'title check' );
}
#diag Dumper( $call->response_hash );
use Test::More;
use strict; no warnings;
#use LWP::Debug qw(+);
use Data::Dumper;
use lib qw/lib/;
BEGIN {
my @skip_msg;
eval {
use eBay::API::Simple::RSS;
};
if ( $@ ) {
push @skip_msg, 'missing module eBay::API::Simple::RSS, skipping test';
}
if ( scalar( @skip_msg ) ) {
plan skip_all => join( ' ', @skip_msg );
}
else {
plan qw(no_plan);
}
}
my $call = eBay::API::Simple::RSS->new();
$call->execute(
'http://worldofgood.ebay.com/Eco-Organic-Clothes-Shoes-Men-Women-Children/43/list',
{ format => 'rss' },
);
if ( $call->has_error() ) {
fail( 'api call failed: ' . $call->errors_as_string() );
}
else {
is( ref $call->response_dom(), 'XML::LibXML::Document', 'response dom' );
is( ref $call->response_hash(), 'HASH', 'response hash' );
ok( $call->nodeContent('title') ne '', 'nodeContent test' );
#diag Dumper( $call->response_hash );
}
$call->execute( 'http://bogusurlexample.com' );
is( $call->has_error(), 1, 'look for error flag' );
ok( $call->errors_as_string() ne '', 'check for error message' );
ok( $call->response_content() ne '', 'check for response content' );
my $call2 = eBay::API::Simple::RSS->new(
{ request_method => 'POST' }
);
$call2->execute(
'http://en.wikipedia.org/w/index.php?title=Special:RecentChanges&feed=rss',
{ page => 1 },
);
is( ref $call2->response_dom(), 'XML::LibXML::Document', 'post response dom' );
is( ref $call2->response_hash(), 'HASH', 'post response hash' );
ok( $call2->nodeContent('title') ne '', 'post nodeContent test' );
ex/05Finding.t view on Meta::CPAN
use Test::More;
use strict; no warnings;
#use LWP::Debug qw(+);
use Data::Dumper;
use lib qw/lib/;
use utf8;
my @skip_msg;
BEGIN {
eval {
use eBay::API::Simple::Finding;
};
if ( $@ ) {
push @skip_msg, 'missing module eBay::API::Simple::Finding, skipping test';
}
if ( scalar( @skip_msg ) ) {
plan skip_all => join( ' ', @skip_msg );
}
else {
plan qw(no_plan);
}
}
my $call;
eval {
$call = eBay::API::Simple::Finding->new(
{ appid => undef } # <----- your appid here
);
};
if ( $@ ) {
push( @skip_msg, $@ );
}
SKIP: {
skip join("\n", @skip_msg), 1 if scalar(@skip_msg);
$call->execute( 'findItemsByKeywords', {
keywords => 'black shoes',
paginationInput => { entriesPerPage => 15 }
} );
#diag $call->request_content;
#diag $call->response_content;
if ( $call->has_error() ) {
fail( 'api call failed: ' . $call->errors_as_string() );
}
else {
is( ref $call->response_dom(), 'XML::LibXML::Document', 'response dom' );
is( ref $call->response_hash(), 'HASH', 'response hash' );
like( $call->nodeContent('timestamp'),
qr/^\d{4}-\d{2}-\d{2}/,
'response timestamp'
);
ok( $call->nodeContent('totalEntries') > 10, 'response total entries' );
#diag( 'total entries: ' . $call->nodeContent('totalEntries') );
#diag( Dumper( $call->response_hash() ) );
}
$call->execute( 'BadCall', { keywords => 'shoe' } );
is( $call->has_error(), 1, 'look for error flag' );
ok( $call->errors_as_string() ne '', 'check for error message' );
ok( $call->response_content() ne '', 'check for response content' );
$call->execute( 'findItemsByKeywords',
{ keywords => 'shoe',
paginationInput => { entriesPerPage => 15 }
} );
is( $call->has_error(), 0, 'error check' );
is( $call->errors_as_string(), '', 'error string check' );
ok( $call->nodeContent('totalEntries') > 10, 'response total entries' );
# now make sure it works with unicode
$call->execute( 'findItemsByKeywords',
{ keywords => '( shoe, bota, sko, schuh, zapato, chaussure, ÏαÏοÏÏÏι, scarpa, ÑÑÑлÑ',
paginationInput => { entriesPerPage => 15 }
} );
is( $call->has_error(), 0, 'error check with unicode characters' );
is( $call->errors_as_string(), '', 'error string check' );
ok( $call->nodeContent('totalEntries') > 10, 'response total entries' );
#diag( Dumper( $call->response_hash() ) );
my @nodes = $call->response_dom->findnodes(
'//item'
);
my $count = 0;
foreach my $n ( @nodes ) {
++$count;
#diag( $n->findvalue('title/text()') );
ok( $n->findvalue('title/text()') ne '', "title check $count" );
}
}
ex/05Finding_utf8.t view on Meta::CPAN
use Test::More;
use strict; no warnings;
#use LWP::Debug qw(+);
use Data::Dumper;
use lib qw/lib/;
use utf8;
my @skip_msg;
BEGIN {
eval {
use eBay::API::Simple::Finding;
};
if ( $@ ) {
push @skip_msg, 'missing module eBay::API::Simple::Finding, skipping test';
}
if ( scalar( @skip_msg ) ) {
plan skip_all => join( ' ', @skip_msg );
}
else {
plan qw(no_plan);
}
}
my $call;
eval {
$call = eBay::API::Simple::Finding->new(
{ appid => undef } # <----- your appid here
);
};
if ( $@ ) {
push( @skip_msg, $@ );
}
SKIP: {
skip join("\n", @skip_msg), 1 if scalar(@skip_msg);
$call->execute( 'findItemsByKeywords', {
#keywords => '(shoe, bota, ÑÑÑлÑ, Alfredo Falcón)',
keywords => 'Falcón',
paginationInput => { entriesPerPage => 15 }
} );
#diag $call->request_content;
#diag $call->response_content;
if ( $call->has_error() ) {
fail( 'api call failed: ' . $call->errors_as_string() );
}
else {
is( ref $call->response_dom(), 'XML::LibXML::Document', 'response dom' );
is( ref $call->response_hash(), 'HASH', 'response hash' );
like( $call->nodeContent('timestamp'),
qr/^\d{4}-\d{2}-\d{2}/,
'response timestamp'
);
ok( $call->nodeContent('totalEntries') > 2, 'response total entries' );
#diag( 'total entries: ' . $call->nodeContent('totalEntries') );
#diag( Dumper( $call->response_hash() ) );
}
$call->execute( 'BadCall', { keywords => 'shoe' } );
is( $call->has_error(), 1, 'look for error flag' );
ok( $call->errors_as_string() ne '', 'check for error message' );
ok( $call->response_content() ne '', 'check for response content' );
$call->execute( 'findItemsByKeywords', { keywords => 'shoe' } );
is( $call->has_error(), 0, 'error check' );
is( $call->errors_as_string(), '', 'error string check' );
ok( $call->nodeContent('totalEntries') > 10, 'response total entries' );
#diag( Dumper( $call->response_hash() ) );
my @nodes = $call->response_dom->findnodes(
'//item'
);
my $count = 0;
foreach my $n ( @nodes ) {
++$count;
#diag( $n->findvalue('title/text()') );
ok( $n->findvalue('title/text()') ne '', "title check $count" );
}
}
ex/06Merchandising.t view on Meta::CPAN
use Test::More;
use strict; no warnings;
#use LWP::Debug qw(+);
use Data::Dumper;
use lib qw/lib/;
my @skip_msg;
BEGIN {
eval {
use eBay::API::Simple::Merchandising;
};
if ( $@ ) {
push @skip_msg, 'missing module eBay::API::Simple::Merchandising, skipping test';
}
if ( scalar( @skip_msg ) ) {
plan skip_all => join( ' ', @skip_msg );
}
else {
plan qw(no_plan);
}
}
my $call;
eval {
$call = eBay::API::Simple::Merchandising->new(
{ appid => undef, } # <----- your appid here
);
};
if ( $@ ) {
push( @skip_msg, $@ );
}
SKIP: {
skip join("\n", @skip_msg), 1 if scalar(@skip_msg);
$call->execute(
'getMostWatchedItems', { maxResults => 1, categoryId => 267 }
);
#diag $call->request_content;
#diag $call->response_content;
if ( $call->has_error() ) {
fail( 'api call failed: ' . $call->errors_as_string() );
}
else {
is( ref $call->response_dom(), 'XML::LibXML::Document', 'response dom' );
is( ref $call->response_hash(), 'HASH', 'response hash' );
like( $call->nodeContent('timestamp'),
qr/^\d{4}-\d{2}-\d{2}/,
'response timestamp'
);
#diag( Dumper( $call->response_hash() ) );
}
$call->execute( 'BadCall', { keywords => 'shoe' } );
is( $call->has_error(), 1, 'look for error flag' );
ok( $call->errors_as_string() ne '', 'check for error message' );
ok( $call->response_content() ne '', 'check for response content' );
$call->execute( 'getSimilarItems', { itemId => 270358046257 } );
#diag $call->request_content;
#diag $call->response_content;
is( $call->has_error(), 0, 'error check' );
is( $call->errors_as_string(), '', 'error string check' );
#diag( Dumper( $call->response_hash() ) );
my @nodes = $call->response_dom->findnodes(
'//item'
);
my $count = 0;
foreach my $n ( @nodes ) {
++$count;
#diag( $n->findvalue('title/text()') );
ok( $n->findvalue('title/text()') ne '', "title check $count" );
}
}
ex/09HalfShopping.t view on Meta::CPAN
use Test::More;
use strict; no warnings;
#use LWP::Debug qw(+);
use Data::Dumper;
use lib qw/lib/;
my @skip_msg;
plan skip_all => join( ' ', 'Skipping Half test - not implemented' );
BEGIN {
eval {
use eBay::API::Simple::Shopping;
};
if ( $@ ) {
push @skip_msg, 'missing module eBay::API::Simple::Shopping, skipping test';
}
if ( scalar( @skip_msg ) ) {
#plan skip_all => join( ' ', @skip_msg );
}
else {
#plan qw(no_plan);
}
}
my $call;
eval {
$call = eBay::API::Simple::Shopping->new(
{ appid => undef, enable_attributes => 1 } # <----- your appid here
);
};
if ( $@ ) {
push( @skip_msg, $@ );
}
SKIP: {
skip join( ' ', @skip_msg), 1 if scalar( @skip_msg );
$call->execute ('FindHalfProducts', {
ProductID => {
type =>'ISBN', content => '0596006306'
},
PageNumber => { content => 1 },
} );
is( ref $call->response_hash(), 'HASH', 'response hash' );
#print $call->request_content() . "\n\n";
#print $call->response_content();
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $title = $call->response_hash->{Products}{Product}{Title};
like( $title, qr/Head First by Lynn Beighley/, "title check" );
is( $call->nodeContent( 'Ack' ), 'Success', 'call was successfull' );
}
lib/eBay/API/Simple.pm view on Meta::CPAN
package eBay::API::Simple;
our $VERSION = '0.29';
=head1 NAME
eBay::API::Simple - Flexible SDK supporting all eBay web services
=head1 DESCRIPTION
This is the base class for the eBay::API::Simple::* libraries that provide
support for all of eBay's web services. This base class does nothing by itself
and must be subclassed to provide the complete web service support.
See base class for complete docs, L<eBay::API::SimpleBase>
=item L<eBay::API::SimpleBase>
=item L<eBay::API::Simple::Parallel>
=item L<eBay::API::Simple::Merchandising>
=item L<eBay::API::Simple::Finding>
=item L<eBay::API::Simple::Shopping>
=item L<eBay::API::Simple::Trading>
=item L<eBay::API::Simple::HTML>
=item L<eBay::API::Simple::JSON>
=item L<eBay::API::Simple::RSS>
=head1 GET THE SOURCE
http://code.google.com/p/ebay-api-simple
=head1 PUBLIC METHODS
=head2 eBay::API::Simple::{subclass}->new()
see subclass for more docs.
=item L<eBay::API::SimpleBase>
=item L<eBay::API::Simple::Parallel>
=item L<eBay::API::Simple::Merchandising>
=item L<eBay::API::Simple::Finding>
=item L<eBay::API::Simple::Shopping>
=item L<eBay::API::Simple::Trading>
=item L<eBay::API::Simple::HTML>
=item L<eBay::API::Simple::JSON>
=item L<eBay::API::Simple::RSS>
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=cut
1;
lib/eBay/API/Simple/Finding.pm view on Meta::CPAN
package eBay::API::Simple::Finding;
use strict;
use warnings;
use base 'eBay::API::SimpleBase';
use HTTP::Request;
use HTTP::Headers;
use XML::Simple;
use Encode;
use utf8;
our $DEBUG = 0;
=head1 NAME
eBay::API::Simple::Finding - Support for eBay's Finding 2.0 web service
=head1 DESCRIPTION
This class provides support for eBay's Finding 2.0 web services.
See http://developer.ebay.com/products/finding/
=head1 USAGE
my $call = eBay::API::Simple::Finding->new(
{ appid => '<your app id here>' }
);
$call->execute( 'findItemsByKeywords', { keywords => 'shoe' } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
print $call->nodeContent( 'timestamp' );
print $call->nodeContent( 'totalEntries' );
my @nodes = $dom->findnodes(
'//item'
);
foreach my $n ( @nodes ) {
print $n->findvalue('title/text()') . "\n";
}
=head1 SANDBOX USAGE
my $call = eBay::API::Simple::Finding->new( {
appid => '<your app id here>',
domain => 'svcs.sandbox.ebay.com',
} );
$call->execute( 'findItemsByKeywords', { keywords => 'shoe' } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
=head1 PUBLIC METHODS
=head2 new( { %options } }
Constructor for the Finding API call
my $call = eBay::API::Simple::Finding->new( {
appid => '<your app id here>'
...
} );
=head3 Options
=over 4
=item appid (required)
This appid is required by the web service. App ids can be obtained at
http://developer.ebay.com
=item siteid
eBay site id to be supplied to the web service endpoint
defaults to EBAY-US
=item domain
domain for the web service endpoint
defaults to svcs.ebay.com
=item service
SOA Service name
defaults to FindingService
=item uri
endpoint URI
defaults to /services/search/FindingService/v1
=item version
Version to be supplied to the web service endpoint
defaults to 1.0.0
=item https
Specifies is the API calls should be made over https.
defaults to 0
=item enable_attributes
This flag adds support for attributes in the request. If enabled request
data notes much be defined like so,
myElement => { content => 'element content', myattr => 'attr value' }
defaults to 0
=back
=head3 ALTERNATE CONFIG VIA ebay.yaml
An ebay.yaml file can be use for configuring each
service endpoint.
YAML files can be placed at the below locations. The first
file found will be loaded.
./ebay.yaml, ~/ebay.yaml, /etc/ebay.yaml
Sample YAML:
# Trading - External
api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
token: <token>
# Shopping
open.api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
version: 671
# Finding/Merchandising
svcs.ebay.com:
appid: <your appid>
version: 1.0.0
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->api_config->{service} ||= 'FindingService';
$self->api_config->{domain} ||= 'svcs.ebay.com';
$self->api_config->{uri} ||= '/services/search/FindingService/v1';
$self->api_config->{version} ||= '1.0.0';
$self->api_config->{https} ||= 0;
$self->api_config->{siteid} ||= 'EBAY-US';
$self->api_config->{response_encoding} ||= 'XML'; # JSON, NV, SOAP
$self->api_config->{request_encoding} ||= 'XML';
$self->_load_yaml_defaults();
if ( $DEBUG ) {
print STDERR sprintf( "API CONFIG:\n%s\n",
$self->api_config_dump()
);
}
$self->_load_credentials();
return $self;
}
=head2 prepare( $verb, $call_data )
$self->prepare( 'findItemsByKeywords', { keywords => 'shoe' } );
This method will construct the API request based on the $verb and
the $call_data.
=item $verb (required)
call verb, i.e. findItemsItemsByKeywords
=item $call_data (required)
hashref of call_data that will be turned into xml.
=cut
sub prepare {
my $self = shift;
$self->{verb} = shift;
$self->{call_data} = shift;
if ( ! defined $self->{verb} || ! defined $self->{call_data} ) {
die "missing verb and call_data";
}
# make sure we have appid
$self->_load_credentials();
}
=head1 BASECLASS METHODS
=head2 request_agent
Accessor for the LWP::UserAgent request agent
=head2 request_object
Accessor for the HTTP::Request request object
=head2 request_content
Accessor for the complete request body from the HTTP::Request object
=head2 response_content
Accessor for the HTTP response body content
=head2 response_object
Accessor for the HTTP::Request response object
=head2 response_dom
Accessor for the LibXML response DOM
=head2 response_hash
Accessor for the hashified response content
=head2 nodeContent( $tag, [ $dom ] )
Helper for LibXML that retrieves node content
=head2 errors
Accessor to the hashref of errors
=head2 has_error
Returns true if the call contains errors
=head2 errors_as_string
Returns a string of API errors if there are any.
=head1 PRIVATE METHODS
=head2 _get_request_body
This method supplies the XML body for the web service request
=cut
sub _get_request_body {
my $self = shift;
# handle a special unicode issue with perl 5.8.1
if ( $self->{call_data}->{keywords} && $] eq '5.008001' ) {
Encode::_utf8_off($self->{call_data}->{keywords});
}
elsif ($self->{call_data}->{keywords}) {
$self->{call_data}->{keywords}
= Encode::encode('utf8', $self->{call_data}->{keywords});
}
my $xml = "<?xml version='1.0' encoding='utf-8'?>"
. "<" . $self->{verb} . "Request xmlns=\"http://www.ebay.com/marketplace/search/v1/services\">"
. XMLout(
$self->{call_data},
NoAttr => !$self->api_config->{enable_attributes},
KeepRoot => 1,
RootName => undef
)
. "</" . $self->{verb} . "Request>";
return $xml;
}
=head2 _get_request_headers
This method supplies the HTTP::Headers obj for the web service request
=cut
sub _get_request_headers {
my $self = shift;
my $obj = HTTP::Headers->new();
$obj->push_header("X-EBAY-SOA-SERVICE-NAME" => $self->api_config->{service});
$obj->push_header("X-EBAY-SOA-SERVICE-VERSION" => $self->api_config->{version});
$obj->push_header("X-EBAY-SOA-SECURITY-APPNAME" => $self->api_config->{appid});
$obj->push_header("X-EBAY-SOA-GLOBAL-ID" => $self->api_config->{siteid});
$obj->push_header("X-EBAY-SOA-OPERATION-NAME" => $self->{verb});
$obj->push_header("X-EBAY-SOA-REQUEST-DATA-FORMAT" => $self->api_config->{request_encoding});
$obj->push_header("X-EBAY-SOA-RESPONSE-DATA-FORMAT" => $self->api_config->{response_encoding});
$obj->push_header("Content-Type" => "text/xml");
return $obj;
}
=head2 _get_request_object
This method creates and returns the HTTP::Request object for the
web service call.
=cut
sub _get_request_object {
my $self = shift;
my $url = sprintf( 'http%s://%s%s',
( $self->api_config->{https} ? 's' : '' ),
$self->api_config->{domain},
$self->api_config->{uri}
);
my $request_obj = HTTP::Request->new(
"POST",
$url,
$self->_get_request_headers,
$self->_get_request_body
);
return $request_obj;
}
sub _load_credentials {
my $self = shift;
# we only need to load credentials once
return if $self->{_credentials_loaded};
my @missing;
# required by the API
for my $p ( qw/appid/ ) {
next if defined $self->api_config->{$p};
if ( my $val = $self->_fish_ebay_ini( $p ) ) {
$self->api_config->{$p} = $val;
}
else {
push( @missing, $p );
}
}
# die if we didn't get everything
if ( scalar @missing > 0 ) {
die "missing API credential: " . join( ", ", @missing );
}
$self->{_credentials_loaded} = 1;
return;
}
sub _fish_ebay_ini {
my $self = shift;
my $arg = shift;
# initialize our hashref
$self->{_ebay_ini} ||= {};
# revert eBay::API::Simple keys to standard keys
$arg = 'ApplicationKey' if $arg eq 'appid';
# return it if we've already found it
return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
# ini files in order of importance
my @files = (
'./ebay.ini',
"$ENV{HOME}/ebay.ini",
'/etc/ebay.ini',
);
foreach my $file ( reverse @files ) {
if ( open( FILE, "<", $file ) ) {
while ( my $line = <FILE> ) {
chomp( $line );
next if $line =~ m!^\s*\#!;
my( $k, $v ) = split( /=/, $line );
if ( defined $k && defined $v) {
$v =~ s/^\s+//;
$v =~ s/\s+$//;
$self->{_ebay_ini}{$k} = $v;
}
}
close FILE;
}
}
return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
return undef;
}
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=cut
1;
lib/eBay/API/Simple/HTML.pm view on Meta::CPAN
package eBay::API::Simple::HTML;
use strict;
use warnings;
use base 'eBay::API::SimpleBase';
use HTTP::Request;
use HTTP::Headers;
use XML::Simple;
use URI::Escape;
use utf8;
our $DEBUG = 0;
=head1 NAME
eBay::API::Simple::HTML - Support for grabbing an HTML page via API call
=head1 USAGE
my $call = eBay::API::Simple::HTML->new();
$call->execute( 'http://en.wikipedia.org/wiki/Main_Page', { a => 'b' } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
# collect all h2 nodes
my @h2 = $dom->getElementsByTagName('h2');
foreach my $n ( @h2 ) {
print $n->findvalue('text()') . "\n";
}
=head1 PUBLIC METHODS
=head2 new( { %options } }
my $call = ebay::API::Simple::HTML->new();
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->api_config->{request_method} ||= 'GET';
return $self;
}
=head2 prepare( $url, $%args )
$call->prepare( 'http://en.wikipedia.org/wiki/Main_Page', { a => 'b' } );
This method will construct the API request based on the $verb and
the $call_data.
=head3 Options
=over 4
=item $url (required)
URL for page to fetch
=item %$args (optional)
The supplied args will be encoded and appended to the URL
=back
=cut
sub prepare {
my $self = shift;
$self->{url} = shift;
if ( ! defined $self->{url} ) {
die "missing url";
}
# collect the optional args
$self->{args} = shift;
}
=head2 response_hash
Custom response_hash method, uses the output from LibXML to generate the
hash instead of the raw response body.
=cut
sub response_hash {
my $self = shift;
if ( ! defined $self->{response_hash} ) {
$self->{response_hash} = XMLin( $self->response_dom->toString(),
forcearray => [],
keyattr => []
);
}
return $self->{response_hash};
}
=head2 response_dom
Custom response_dom method, provides a more relaxed parsing to better handle HTML.
=cut
sub response_dom {
my $self = shift;
if ( ! defined $self->{response_dom} ) {
require XML::LibXML;
my $parser = XML::LibXML->new();
$parser->recover(1);
$parser->recover_silently(1);
eval {
$self->{response_dom} =
$parser->parse_html_string( $self->response_content );
};
if ( $@ ) {
$self->errors_append( { 'parsing_error' => $@ } );
}
}
return $self->{response_dom};
}
=head1 BASECLASS METHODS
=head2 request_agent
Accessor for the LWP::UserAgent request agent
=head2 request_object
Accessor for the HTTP::Request request object
=head2 request_content
Accessor for the complete request body from the HTTP::Request object
=head2 response_content
Accessor for the HTTP response body content
=head2 response_object
Accessor for the HTTP::Request response object
=head2 nodeContent( $tag, [ $dom ] )
Helper for LibXML that retrieves node content
=head2 errors
Accessor to the hashref of errors
=head2 has_error
Returns true if the call contains errors
=head2 errors_as_string
Returns a string of API errors if there are any.
=head1 PRIVATE METHODS
=head2 _get_request_body
This method supplies the XML body for the web service request
=cut
sub _get_request_body {
my $self = shift;
my @p;
if ( $self->api_config->{request_method} ne 'GET' ) {
for my $k ( keys %{ $self->{args} } ) {
push( @p, ( $k . '=' . uri_escape( $self->{args}{$k} ) ) );
}
}
return join( '&', @p ) or "";
}
=head2 _get_request_headers
This methods supplies the headers for the HTML API call
=cut
sub _get_request_headers {
my $self = shift;
my $obj = HTTP::Headers->new();
return $obj;
}
=head2 _get_request_object
This method creates the request object and returns to the parent class
=cut
sub _get_request_object {
my $self = shift;
my $req_url = undef;
# put the args in the url for a GET request only
if ( $self->api_config->{request_method} eq 'GET'
&& defined $self->{args} ) {
$req_url = $self->_build_url( $self->{url}, $self->{args} );
}
else {
$req_url = $self->{url};
}
my $request_obj = HTTP::Request->new(
( $self->api_config->{request_method} || 'GET' ),
$req_url,
$self->_get_request_headers,
$self->_get_request_body,
);
if( $self->api_config->{authorization_basic}{enabled} ) {
$request_obj->authorization_basic(
$self->api_config->{authorization_basic}{username},
$self->api_config->{authorization_basic}{password}
);
}
return $request_obj;
}
1;
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=head1 COPYRIGHT
Tim Keefer 2009
=cut
lib/eBay/API/Simple/JSON.pm view on Meta::CPAN
package eBay::API::Simple::JSON;
use strict;
use warnings;
use base 'eBay::API::SimpleBase';
use JSON;
use HTTP::Request;
use HTTP::Headers;
use XML::Simple;
use URI::Escape;
use utf8;
our $DEBUG = 0;
=head1 NAME
eBay::API::Simple::JSON - Support for grabbing an RSS feed via API call
=head1 USAGE
my $api = eBay::API::Simple::JSON->new();
my $data = {
"user_eais_token" => "tim",
"body_text" => "mytext",
"foo" => "bar",
"greener_alt_topic" => "/green/api/v1/greenerAlternativeTopic/2/",
"items"=> [ {
"ebay_item_id"=> "250814913221",
"photo"=> "http=>//thumbs2.ebaystatic.com/m/m9X7sXOK303v4e_fgxm_-7w/140.jpg",
"price"=> 2.96,
"title"=> "TEST PUT - VAPUR 16 OZ FLEXIBLE FOLDABLE WATER BOTTLE BPA FREE"
} ],
"meta_title"=> "Foldable bottles can be stashed away when the water is gone",
"title"=> "TEST PUT - Foldable bottles can be stashed away when the water is gone"
};
$api->execute(
'http://localhost-django-vm.ebay.com/green/api/v1/greenerAlternative/',
$data
);
print $api->request_content() ."\n";
if ( $api->has_error() ) {
print "FAILED: " . $api->response_content();
#print "FAILED: " . $api->response_hash->{error_message} . "\n";
}
else {
print "SUCCESS!\n";
print $api->response_object->header('Location') . "\n";
}
my $hash = $call->response_hash();
# execution methods for "GET", "POST", "PUT", and "DELETE" requests
$api->get( $endpoint );
$api->post( $endpoint, data );
$api->put( $endpoint, $data );
$api->delete( $endpoint );
=head1 PUBLIC METHODS
=head2 new( { %options } }
my $call = ebay::API::Simple::JSON->new();
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->api_config->{request_method} ||= 'POST';
return $self;
}
=head2 prepare( $url, $%args )
$call->prepare(
'http://sfbay.craigslist.org/search/sss',
{ query => 'shirt', format => 'rss', }
);
This method will construct the API request using the supplied URL.
=head3 Options
=over 4
=item $url (required)
Feed URL to fetch
=item %$args (optional)
The supplied args will be encoded and appended to the URL
=back
=cut
sub prepare {
my $self = shift;
$self->{url} = shift;
if ( ! defined $self->{url} ) {
die "missing url";
}
# collect the optional args
$self->{request_data} = shift;
}
=head2 process()
This method will process the API response.
=cut
sub process {
my $self = shift;
$self->SUPER::process();
$self->response_hash(); # build the hash now to detect errors
}
=head2 get( $url )
execute a "GET" request to the specified endpoint
=cut
sub get {
my $self = shift;
$self->{custom_method} = 'GET';
$self->execute(@_);
$self->{custom_method} = undef;
}
=head2 post( $url )
execute a "POST" request to the specified endpoint
=cut
sub post {
my $self = shift;
$self->{custom_method} = 'POST';
$self->execute(@_);
$self->{custom_method} = undef;
}
=head2 put( $url )
execute a "PUT" request to the specified endpoint
=cut
sub put {
my $self = shift;
$self->{custom_method} = 'PUT';
$self->execute(@_);
$self->{custom_method} = undef;
}
=head2 delete( $url )
execute a "DELETE" request to the specified endpoint
=cut
sub delete {
my $self = shift;
$self->{custom_method} = 'DELETE';
$self->execute(@_);
$self->{custom_method} = undef;
}
=head1 BASECLASS METHODS
=head2 request_agent
Accessor for the LWP::UserAgent request agent
=head2 request_object
Accessor for the HTTP::Request request object
=head2 request
Accessor for the HTTP::Request request object
=cut
sub request {
my $self = shift;
return $self->request_object();
}
=head2 request_content
Accessor for the complete request body from the HTTP::Request object
=head2 response_content
Accessor for the HTTP response body content
=head2 response_object
Accessor for the HTTP::Response response object
=head2 response
Accessor for the HTTP::Response response object
=cut
sub response {
my $self = shift;
return $self->response_object;
}
=head2 response_dom
Accessor for the LibXML response DOM
=cut
sub response_dom {
die "can't use with the JSON backend";
}
=head2 response_hash
Accessor for the hashified response content
=cut
sub response_hash {
my $self = shift;
if ( ! defined $self->{response_hash} && $self->response_content ) {
eval {
$self->{response_hash} = decode_json( $self->response_content );
};
if ( $@ ) {
$self->errors_append( { 'decode_error' => $@ } );
}
}
return $self->{response_hash};
}
=head2 response_json
Accessor for the json response content
=cut
sub response_json {
my $self = shift;
return $self->response_content;
}
=head2 nodeContent( $tag, [ $dom ] )
Helper for LibXML that retrieves node content
=cut
sub nodeContent {
die "not implemented for the JSON backend";
}
=head2 errors
Accessor to the hashref of errors
=head2 has_error
Returns true if the call contains errors
=cut
sub has_error {
my $self = shift;
my $has_error = (keys( %{ $self->errors } ) > 0) ? 1 : 0;
return 1 if $has_error;
return $self->response_object->is_error;
}
=head2 errors_as_string
Returns a string of API errors if there are any.
=cut
sub errors_as_string {
my $self = shift;
return "" unless $self->has_error;
my @e;
for my $k ( keys %{ $self->errors } ) {
push( @e, $k . '-' . $self->errors->{$k} );
}
if ( $self->response_object->is_error ) {
push( @e, $self->response_content );
}
return join( "\n", @e );
}
=head1 PRIVATE METHODS
=head2 _get_request_body
This method supplies the JSON body for the web service request
=cut
sub _get_request_body {
my $self = shift;
return undef if ! defined $self->{request_data};
my $body;
eval {
my $json = JSON->new->utf8;
$body = $json->allow_blessed->convert_blessed->encode( $self->{request_data} );
};
if ( $@ ) {
$self->errors_append( { 'decode_error' => $@ } );
}
return $body;
}
=head2 _get_request_headers
This methods supplies the headers for the RSS API call
=cut
sub _get_request_headers {
my $self = shift;
my $obj = HTTP::Headers->new();
$obj->push_header( 'Content-Type' => 'application/json' );
return $obj;
}
=head2 _get_request_object
This method creates the request object and returns to the parent class
=cut
sub _get_request_object {
my $self = shift;
my $body = $self->_get_request_body;
my $request_method = $self->{custom_method};
if ( ! $request_method ) {
$request_method = defined $body ? 'POST' : 'GET';
}
my $request_obj = HTTP::Request->new(
$request_method,
$self->{url},
$self->_get_request_headers,
$self->_get_request_body,
);
if( $self->api_config->{authorization_basic}{enabled} ) {
$request_obj->authorization_basic(
$self->api_config->{authorization_basic}{username},
$self->api_config->{authorization_basic}{password}
);
}
return $request_obj;
}
1;
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=head1 COPYRIGHT
Tim Keefer 2009
=cut
lib/eBay/API/Simple/Merchandising.pm view on Meta::CPAN
package eBay::API::Simple::Merchandising;
use strict;
use warnings;
use base 'eBay::API::SimpleBase';
use HTTP::Request;
use HTTP::Headers;
use XML::Simple;
use utf8;
our $DEBUG = 0;
=head1 NAME
eBay::API::Simple::Merchandising - Support for eBay's Merchandising web service
=head1 DESCRIPTION
This class provides support for eBay's Merchandising web services.
See http://developer.ebay.com/products/merchandising/
=head1 USAGE
my $call = eBay::API::Simple::Merchandising->new(
{ appid => '<your app id here>' }
);
$call->execute( 'getMostWatchedItems', { maxResults => 3, categoryId => 267 } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
print $call->nodeContent( 'timestamp' );
print $call->nodeContent( 'totalEntries' );
my @nodes = $dom->findnodes(
'//item'
);
foreach my $n ( @nodes ) {
print $n->findvalue('title/text()') . "\n";
}
=head1 SANDBOX USAGE
my $call = eBay::API::Simple::Merchandising->new( {
appid => '<your app id here>'
domain => '',
} );
$call->execute( 'getMostWatchedItems', { maxResults => 3, categoryId => 267 } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
=head1 PUBLIC METHODS
=head2 new( { %options } }
Constructor for the Finding API call
my $call = eBay::API::Simple::Merchandising->new( {
appid => '<your app id here>'
...
} );
=head3 Options
=over 4
=item appid (required)
This appid is required by the web service. App ids can be obtained at
http://developer.ebay.com
=item siteid
eBay site id to be supplied to the web service endpoint
defaults to EBAY-US
=item domain
domain for the web service endpoint
defaults to svcs.ebay.com
=item uri
endpoint URI
defaults to /MerchandisingService
=item version
Version to be supplied to the web service endpoint
defaults to 1.0.0
=item https
Specifies is the API calls should be made over https.
defaults to 0
=item enable_attributes
This flag adds support for attributes in the request. If enabled request
data notes much be defined like so,
myElement => { content => 'element content', myattr => 'attr value' }
defaults to 0
=back
=head3 ALTERNATE CONFIG VIA ebay.yaml
An ebay.yaml file can be used for configuring each
service endpoint.
YAML files can be placed at the below locations. The first
file found will be loaded.
./ebay.yaml, ~/ebay.yaml, /etc/ebay.yaml
Sample YAML:
# Trading - External
api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
token: <token>
# Shopping
open.api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
version: 671
# Finding/Merchandising
svcs.ebay.com:
appid: <your appid>
version: 1.0.0
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->api_config->{domain} ||= 'svcs.ebay.com';
$self->api_config->{uri} ||= '/MerchandisingService';
#$self->api_config->{version} ||= '1.1.0';
$self->api_config->{https} ||= 0;
$self->api_config->{siteid} ||= 'EBAY-US';
$self->api_config->{response_encoding} ||= 'XML'; # JSON, NV, SOAP
$self->api_config->{request_encoding} ||= 'XML';
$self->_load_yaml_defaults();
if ( $DEBUG ) {
print STDERR sprintf( "API CONFIG:\n%s\n",
$self->api_config_dump()
);
}
$self->_load_credentials();
return $self;
}
=head2 prepare( $verb, $call_data )
$self->prepare( 'getMostWatchedItems', { maxResults => 3, categoryId => 267 } );
This method will construct the API request based on the $verb and
the $call_data.
=item $verb (required)
call verb, i.e. getMostWatchedItems
=item $call_data (required)
hashref of call_data that will be turned into xml.
=cut
sub prepare {
my $self = shift;
$self->{verb} = shift;
$self->{call_data} = shift;
if ( ! defined $self->{verb} || ! defined $self->{call_data} ) {
die "missing verb and call_data";
}
# make sure we have appid
$self->_load_credentials();
}
=head1 BASECLASS METHODS
=head2 request_agent
Accessor for the LWP::UserAgent request agent
=head2 request_object
Accessor for the HTTP::Request request object
=head2 request_content
Accessor for the complete request body from the HTTP::Request object
=head2 response_content
Accessor for the HTTP response body content
=head2 response_object
Accessor for the HTTP::Request response object
=head2 response_dom
Accessor for the LibXML response DOM
=head2 response_hash
Accessor for the hashified response content
=head2 nodeContent( $tag, [ $dom ] )
Helper for LibXML that retrieves node content
=head2 errors
Accessor to the hashref of errors
=head2 has_error
Returns true if the call contains errors
=head2 errors_as_string
Returns a string of API errors if there are any.
=head1 PRIVATE METHODS
=head2 _get_request_body
This method supplies the XML body for the web service request
=cut
sub _get_request_body {
my $self = shift;
my $xml = "<?xml version='1.0' encoding='utf-8'?>"
. "<" . $self->{verb} . "Request xmlns=\"http://www.ebay.com/marketplace/services\">"
. XMLout(
$self->{call_data},
NoAttr => !$self->api_config->{enable_attributes},
KeepRoot => 1,
RootName => undef
)
. "</" . $self->{verb} . "Request>";
return $xml;
}
=head2 _get_request_headers
This method supplies the HTTP::Headers obj for the web service request
=cut
sub _get_request_headers {
my $self = shift;
my $obj = HTTP::Headers->new();
if ( defined $self->api_config->{version} ) {
$obj->push_header("X-EBAY-SOA-SERVICE-VERSION"
=> $self->api_config->{version});
}
$obj->push_header("X-EBAY-SOA-SERVICE-NAME" => "MerchandisingService" );
$obj->push_header("EBAY-SOA-CONSUMER-ID" => $self->api_config->{appid});
$obj->push_header("X-EBAY-SOA-GLOBAL-ID" => $self->api_config->{siteid});
$obj->push_header("X-EBAY-SOA-OPERATION-NAME" => $self->{verb});
$obj->push_header("X-EBAY-SOA-REQUEST-DATA-FORMAT"
=> $self->api_config->{request_encoding});
$obj->push_header("X-EBAY-SOA-RESPONSE-DATA-FORMAT"
=> $self->api_config->{response_encoding});
$obj->push_header("Content-Type" => "text/xml");
return $obj;
}
=head2 _get_request_object
This method creates and returns the HTTP::Request object for the
web service call.
=cut
sub _get_request_object {
my $self = shift;
my $url = sprintf( 'http%s://%s%s',
( $self->api_config->{https} ? 's' : '' ),
$self->api_config->{domain},
$self->api_config->{uri}
);
my $request_obj = HTTP::Request->new(
"POST",
$url,
$self->_get_request_headers,
$self->_get_request_body
);
return $request_obj;
}
sub _load_credentials {
my $self = shift;
# we only need to load credentials once
return if $self->{_credentials_loaded};
my @missing;
# required by the API
for my $p ( qw/appid/ ) {
next if defined $self->api_config->{$p};
if ( my $val = $self->_fish_ebay_ini( $p ) ) {
$self->api_config->{$p} = $val;
}
else {
push( @missing, $p );
}
}
# die if we didn't get everything
if ( scalar @missing > 0 ) {
die "missing API credential: " . join( ", ", @missing );
}
$self->{_credentials_loaded} = 1;
return;
}
sub _fish_ebay_ini {
my $self = shift;
my $arg = shift;
# initialize our hashref
$self->{_ebay_ini} ||= {};
# revert eBay::API::Simple keys to standard keys
$arg = 'ApplicationKey' if $arg eq 'appid';
# return it if we've already found it
return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
# ini files in order of importance
my @files = (
'./ebay.ini',
"$ENV{HOME}/ebay.ini",
'/etc/ebay.ini',
);
foreach my $file ( reverse @files ) {
if ( open( FILE, "<", $file ) ) {
while ( my $line = <FILE> ) {
chomp( $line );
next if $line =~ m!^\s*\#!;
my( $k, $v ) = split( /=/, $line );
if ( defined $k && defined $v) {
$v =~ s/^\s+//;
$v =~ s/\s+$//;
$self->{_ebay_ini}{$k} = $v;
}
}
close FILE;
}
}
return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
return undef;
}
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=cut
1;
lib/eBay/API/Simple/Parallel.pm view on Meta::CPAN
package eBay::API::Simple::Parallel;
use strict;
use warnings;
use base 'LWP::Parallel::UserAgent';
use utf8;
our $DEBUG = 0;
=head1 NAME
eBay::API::Simple::Parallel - Support for parallel requests
=head1 USAGE
my $pua = eBay::API::Simple::Parallel->new();
my $call1 = eBay::API::Simple::RSS->new( {
parallel => $pua,
} );
$call1->execute(
'http://worldofgood.ebay.com/Clothes-Shoes-Men/43/list?format=rss',
);
my $call2 = eBay::API::Simple::RSS->new( {
parallel => $pua,
} );
$call2->execute(
'http://worldofgood.ebay.com/Home-Garden/46/list?format=rss'
);
$pua->wait();
if ( $pua->has_error() ) {
print "ONE OR MORE FAILURES!\n";
}
print $call1->request_content() . "\n";
print $call2->response_content() "\n";
=head1 PUBLIC METHODS
=head2 new()
my $pua = ebay::API::Simple::Parallel->new();
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new( @_ );
$self->{has_error} = 0;
return $self;
}
=head2 wait( $timeout )
$pua->wait();
This method will wait for all requests to complete with an optional timeout.
An array of object instances will be returned.
=cut
sub wait {
my $self = shift;
my $timeout = shift;
my @objects;
my $entries = $self->SUPER::wait( $timeout );
for my $key ( keys %$entries ) {
push( @objects, $entries->{$key}->request->{_ebay_api_simple_instance} );
delete( $entries->{$key}->request->{_ebay_api_simple_instance}->{parallel} );
delete( $entries->{$key}->request->{_ebay_api_simple_instance} );
}
return \@objects;
}
=head2 has_error
Returns true if any of the calls contain an error.
=cut
sub has_error {
my $self = shift;
return $self->{has_error};
}
sub on_connect {
my $self = shift;
my $request = shift;
my $response = shift;
my $entry = shift;
if( $DEBUG ) {
print STDERR "Parallel Connect: " . $request->url . "\n";
}
}
sub on_return {
my $self = shift;
my $request = shift;
my $response = shift;
my $entry = shift;
if( $DEBUG ) {
print STDERR "Parallel Return: " . $request->url . "\n";
}
$request->{_ebay_api_simple_instance}->_process_http_request( $response );
$request->{_ebay_api_simple_instance}->process();
if( $request->{_ebay_api_simple_instance}->has_error ) {
$self->{has_error} = 1;
}
}
sub on_failure {
my $self = shift;
my $request = shift;
my $response = shift;
my $entry = shift;
if( $DEBUG ) {
print STDERR "Parallel Failure: " . $request->url . "\n";
}
$request->{_ebay_api_simple_instance}->_process_http_request( $response );
$request->{_ebay_api_simple_instance}->process();
$self->{has_error} = 1;
}
1;
=head1 AUTHOR
Brian Gontowski <bgontowski@gmail.com>
=cut
lib/eBay/API/Simple/RSS.pm view on Meta::CPAN
package eBay::API::Simple::RSS;
use strict;
use warnings;
use base 'eBay::API::SimpleBase';
use HTTP::Request;
use HTTP::Headers;
use XML::Simple;
use URI::Escape;
use utf8;
our $DEBUG = 0;
=head1 NAME
eBay::API::Simple::RSS - Support for grabbing an RSS feed via API call
=head1 USAGE
my $call = eBay::API::Simple::RSS->new();
$call->execute(
'http://sfbay.craigslist.org/search/sss',
{
query => 'shirt',
format => 'rss',
}
);
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
# collect all item nodes
my @items = $dom->getElementsByTagName('item');
foreach my $n ( @items ) {
print $n->findvalue('title/text()') . "\n";
}
=head1 PUBLIC METHODS
=head2 new( { %options } }
my $call = ebay::API::Simple::RSS->new();
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->api_config->{request_method} ||= 'GET';
return $self;
}
=head2 prepare( $url, $%args )
$call->prepare(
'http://sfbay.craigslist.org/search/sss',
{ query => 'shirt', format => 'rss', }
);
This method will construct the API request using the supplied URL.
=head3 Options
=over 4
=item $url (required)
Feed URL to fetch
=item %$args (optional)
The supplied args will be encoded and appended to the URL
=back
=cut
sub prepare {
my $self = shift;
$self->{url} = shift;
if ( ! defined $self->{url} ) {
die "missing url";
}
# collect the optional args
$self->{args} = shift;
}
=head1 BASECLASS METHODS
=head2 request_agent
Accessor for the LWP::UserAgent request agent
=head2 request_object
Accessor for the HTTP::Request request object
=head2 request_content
Accessor for the complete request body from the HTTP::Request object
=head2 response_content
Accessor for the HTTP response body content
=head2 response_object
Accessor for the HTTP::Request response object
=head2 response_dom
Accessor for the LibXML response DOM
=head2 response_hash
Accessor for the hashified response content
=head2 nodeContent( $tag, [ $dom ] )
Helper for LibXML that retrieves node content
=head2 errors
Accessor to the hashref of errors
=head2 has_error
Returns true if the call contains errors
=head2 errors_as_string
Returns a string of API errors if there are any.
=head1 PRIVATE METHODS
=head2 _get_request_body
This method supplies the XML body for the web service request
=cut
sub _get_request_body {
my $self = shift;
my @p;
if ( $self->api_config->{request_method} ne 'GET' ) {
for my $k ( keys %{ $self->{args} } ) {
if ( ref( $self->{args}{$k} ) eq 'ARRAY' ) {
for my $ap ( @{ $self->{args}{$k} } ) {
push( @p,
( $k . '=' . uri_escape_utf8( $ap ) )
);
}
}
else {
push( @p, ( $k . '=' . uri_escape_utf8( $self->{args}{$k} ) ) );
}
}
}
return join( '&', @p ) or "";
}
=head2 _get_request_headers
This methods supplies the headers for the RSS API call
=cut
sub _get_request_headers {
my $self = shift;
my $obj = HTTP::Headers->new();
return $obj;
}
=head2 _get_request_object
This method creates the request object and returns to the parent class
=cut
sub _get_request_object {
my $self = shift;
my $req_url = undef;
# put the args in the url for a GET request only
if ( $self->api_config->{request_method} eq 'GET'
&& defined $self->{args} ) {
$req_url = $self->_build_url( $self->{url}, $self->{args} );
}
else {
$req_url = $self->{url};
}
my $request_obj = HTTP::Request->new(
( $self->api_config->{request_method} || 'GET' ),
$req_url,
$self->_get_request_headers,
$self->_get_request_body,
);
if( $self->api_config->{authorization_basic}{enabled} ) {
$request_obj->authorization_basic(
$self->api_config->{authorization_basic}{username},
$self->api_config->{authorization_basic}{password}
);
}
return $request_obj;
}
1;
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=head1 COPYRIGHT
Tim Keefer 2009
=cut
lib/eBay/API/Simple/Shopping.pm view on Meta::CPAN
package eBay::API::Simple::Shopping;
use strict;
use warnings;
use base 'eBay::API::SimpleBase';
use HTTP::Request;
use HTTP::Headers;
use XML::Simple;
use utf8;
our $DEBUG = 0;
=head1 NAME
eBay::API::Simple::Shopping - Support for eBay's Shopping web service
=head1 DESCRIPTION
This class provides support for eBay's Shopping web services.
See http://developer.ebay.com/products/shopping/
=head1 USAGE
my $call = eBay::API::Simple::Shopping->new(
{ appid => '<your app id here>' }
);
$call->execute( 'FindItemsAdvanced', { QueryKeywords => 'shoe' } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
print $call->nodeContent( 'Timestamp' );
print $call->nodeContent( 'TotalItems' );
my @nodes = $dom->findnodes(
'/FindItemsAdvancedResponse/SearchResult/ItemArray/Item'
);
foreach my $n ( @nodes ) {
print $n->findvalue('Title/text()') . "\n";
}
=head1 SANDBOX USAGE
my $call = eBay::API::Simple::Shopping->new( {
appid => '<your app id here>',
domain => 'open.api.sandbox.ebay.com',
} );
$call->execute( 'FindItemsAdvanced', { QueryKeywords => 'shoe' } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
=head1 PUBLIC METHODS
=head2 new( { %options } }
Constructor for the Finding API call
my $call = eBay::API::Simple::Shopping->new( {
appid => '<your app id here>'
...
} );
=head3 Options
=over 4
=item appid (required)
This appid is required by the web service. App ids can be obtained at
http://developer.ebay.com
=item siteid
eBay site id to be supplied to the web service endpoint
defaults to 0
=item domain
domain for the web service endpoint
defaults to open.api.ebay.com
=item uri
endpoint URI
defaults to /shopping
=item version
Version to be supplied to the web service endpoint
defaults to 527
=item https
Specifies is the API calls should be made over https.
defaults to 0
=item enable_attributes
This flag adds support for attributes in the request. If enabled request
data notes much be defined like so,
myElement => { content => 'element content', myattr => 'attr value' }
defaults to 0
=back
=head3 ALTERNATE CONFIG VIA ebay.yaml
An ebay.yaml file can be used for configuring each
service endpoint.
YAML files can be placed at the below locations. The first
file found will be loaded.
./ebay.yaml, ~/ebay.yaml, /etc/ebay.yaml
Sample YAML:
# Trading - External
api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
token: <token>
# Shopping
open.api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
version: 671
# Finding/Merchandising
svcs.ebay.com:
appid: <your appid>
version: 1.0.0
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->api_config->{domain} ||= 'open.api.ebay.com';
$self->api_config->{uri} ||= '/shopping';
$self->api_config->{version} ||= '527';
$self->api_config->{https} ||= 0;
$self->api_config->{siteid} ||= 0;
$self->api_config->{response_encoding} ||= 'XML'; # JSON, NV, SOAP
$self->api_config->{request_encoding} ||= 'XML';
$self->_load_yaml_defaults();
if ( $DEBUG ) {
print STDERR sprintf( "API CONFIG:\n%s\n",
$self->api_config_dump()
);
}
$self->_load_credentials();
return $self;
}
=head2 prepare( $verb, $call_data )
$self->prepare( 'FindItemsAdvanced', { QueryKeywords => 'shoe' } );
This method will construct the API request based on the $verb and
the $call_data.
=item $verb (required)
call verb, i.e. FindItemsAdvanced
=item $call_data (required)
hashref of call_data that will be turned into xml.
=cut
sub prepare {
my $self = shift;
$self->{verb} = shift;
$self->{call_data} = shift;
if ( ! defined $self->{verb} || ! defined $self->{call_data} ) {
die "missing verb and call_data";
}
# make sure we have appid
$self->_load_credentials();
}
=head1 BASECLASS METHODS
=head2 request_agent
Accessor for the LWP::UserAgent request agent
=head2 request_object
Accessor for the HTTP::Request request object
=head2 request_content
Accessor for the complete request body from the HTTP::Request object
=head2 response_content
Accessor for the HTTP response body content
=head2 response_object
Accessor for the HTTP::Request response object
=head2 response_dom
Accessor for the LibXML response DOM
=head2 response_hash
Accessor for the hashified response content
=head2 nodeContent( $tag, [ $dom ] )
Helper for LibXML that retrieves node content
=head2 errors
Accessor to the hashref of errors
=head2 has_error
Returns true if the call contains errors
=head2 errors_as_string
Returns a string of API errors if there are any.
=head1 PRIVATE METHODS
=head2 _get_request_body
This method supplies the XML body for the web service request
=cut
sub _get_request_body {
my $self = shift;
my $xml = "<?xml version='1.0' encoding='utf-8'?>"
. "<" . $self->{verb} . "Request xmlns=\"urn:ebay:apis:eBLBaseComponents\">"
. XMLout(
$self->{call_data},
NoAttr => !$self->api_config->{enable_attributes},
KeepRoot => 1,
RootName => undef
)
. "</" . $self->{verb} . "Request>";
return $xml;
}
=head2 _get_request_headers
This method supplies the HTTP::Headers obj for the web service request
=cut
sub _get_request_headers {
my $self = shift;
my $obj = HTTP::Headers->new();
$obj->push_header("X-EBAY-API-VERSION" => $self->api_config->{version});
$obj->push_header("X-EBAY-API-APP-ID" => $self->api_config->{appid});
$obj->push_header("X-EBAY-API-SITEID" => $self->api_config->{siteid});
$obj->push_header("X-EBAY-API-CALL-NAME" => $self->{verb});
$obj->push_header("X-EBAY-API-REQUEST-ENCODING" => $self->api_config->{request_encoding});
$obj->push_header("X-EBAY-API-RESPONSE-ENCODING" => $self->api_config->{response_encoding});
$obj->push_header("Content-Type" => "text/xml");
return $obj;
}
=head2 _get_request_object
This method creates and returns the HTTP::Request object for the
web service call.
=cut
sub _get_request_object {
my $self = shift;
my $url = sprintf( 'http%s://%s%s',
( $self->api_config->{https} ? 's' : '' ),
$self->api_config->{domain},
$self->api_config->{uri}
);
my $request_obj = HTTP::Request->new(
"POST",
$url,
$self->_get_request_headers,
$self->_get_request_body
);
return $request_obj;
}
sub _load_credentials {
my $self = shift;
# we only need to load credentials once
return if $self->{_credentials_loaded};
my @missing;
# required by the API
for my $p ( qw/appid/ ) {
next if defined $self->api_config->{$p};
if ( my $val = $self->_fish_ebay_ini( $p ) ) {
$self->api_config->{$p} = $val;
}
else {
push( @missing, $p );
}
}
# die if we didn't get everything
if ( scalar @missing > 0 ) {
die "missing API credential: " . join( ", ", @missing );
}
$self->{_credentials_loaded} = 1;
return;
}
sub _fish_ebay_ini {
my $self = shift;
my $arg = shift;
# initialize our hashref
$self->{_ebay_ini} ||= {};
# revert eBay::API::Simple keys to standard keys
$arg = 'ApplicationKey' if $arg eq 'appid';
# return it if we've already found it
return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
# ini files in order of importance
my @files = (
'./ebay.ini',
"$ENV{HOME}/ebay.ini",
'/etc/ebay.ini',
);
foreach my $file ( reverse @files ) {
if ( open( FILE, "<", $file ) ) {
while ( my $line = <FILE> ) {
chomp( $line );
next if $line =~ m!^\s*\#!;
my( $k, $v ) = split( /=/, $line );
if ( defined $k && defined $v) {
$v =~ s/^\s+//;
$v =~ s/\s+$//;
$self->{_ebay_ini}{$k} = $v;
}
}
close FILE;
}
}
return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
return undef;
}
1;
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=cut
lib/eBay/API/Simple/Trading.pm view on Meta::CPAN
package eBay::API::Simple::Trading;
use strict;
use warnings;
use base 'eBay::API::SimpleBase';
use HTTP::Request;
use HTTP::Headers;
use XML::Simple;
use utf8;
our $DEBUG = 0;
=head1 NAME
eBay::API::Simple::Trading - Support for eBay's Trading web service
=head1 DESCRIPTION
This class provides support for eBay's Trading web services.
See http://developer.ebay.com/products/trading/
=head1 USAGE
my $call = eBay::API::Simple::Trading->new( {
appid => '<your appid>',
devid => '<your devid>',
certid => '<your certid>',
token => '<auth token>',
} );
$call->execute( 'GetSearchResults', { Query => 'shoe' } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
print $call->nodeContent( 'Timestamp' );
my @nodes = $dom->findnodes(
'//Item'
);
foreach my $n ( @nodes ) {
print $n->findvalue('Title/text()') . "\n";
}
=head1 SANDBOX USAGE
my $call = eBay::API::Simple::Trading->new( {
appid => '<your appid>',
devid => '<your devid>',
certid => '<your certid>',
token => '<auth token>',
domain => 'api.sandbox.ebay.com',
} );
$call->execute( 'GetSearchResults', { Query => 'shoe' } );
if ( $call->has_error() ) {
die "Call Failed:" . $call->errors_as_string();
}
# getters for the response DOM or Hash
my $dom = $call->response_dom();
my $hash = $call->response_hash();
=head1 PUBLIC METHODS
=head2 new( { %options } }
Constructor for the Trading API call
my $call = eBay::API::Simple::Trading->new( {
appid => '<your appid>',
devid => '<your devid>',
certid => '<your certid>',
token => '<auth token>',
...
} );
=head3 Options
=over 4
=item appid (required)
This is required by the web service and can be obtained at
http://developer.ebay.com
=item devid (required)
This is required by the web service and can be obtained at
http://developer.ebay.com
=item certid (required)
This is required by the web service and can be obtained at
http://developer.ebay.com
=item token (required)
This is required by the web service and can be obtained at
http://developer.ebay.com
=item siteid
eBay site id to be supplied to the web service endpoint
defaults to 0
=item domain
domain for the web service endpoint
defaults to open.api.ebay.com
=item uri
endpoint URI
defaults to /ws/api.dll
=item version
Version to be supplied to the web service endpoint
defaults to 543
=item https
Specifies is the API calls should be made over https.
defaults to 1
=item enable_attributes
This flag adds support for attributes in the request. If enabled request
data notes much be defined like so,
myElement => { content => 'element content', myattr => 'attr value' }
defaults to 0
=back
=head3 ALTERNATE CONFIG VIA ebay.yaml
An ebay.yaml file can be used for configuring each
service endpoint.
YAML files can be placed at the below locations. The first
file found will be loaded.
./ebay.yaml, ~/ebay.yaml, /etc/ebay.yaml
Sample YAML:
# Trading - External
api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
token: <token>
# Shopping
open.api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
version: 671
# Finding/Merchandising
svcs.ebay.com:
appid: <your appid>
version: 1.0.0
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->api_config->{domain} ||= 'api.ebay.com';
$self->api_config->{uri} ||= '/ws/api.dll';
$self->api_config->{version} ||= '543';
unless ( defined $self->api_config->{https} ) {
$self->api_config->{https} = 1;
}
unless ( defined $self->api_config->{siteid} ) {
$self->api_config->{siteid} = 0;
}
$self->_load_yaml_defaults();
if ( $DEBUG ) {
print STDERR sprintf( "API CONFIG:\n%s\n",
$self->api_config_dump()
);
}
return $self;
}
=head2 prepare( $verb, $call_data )
$call->prepare( 'GetSearchResults', { Query => 'shoe' } );
This method will construct the API request based on the $verb and
the $call_data.
=item $verb (required)
call verb, i.e. GetSearchResults
=item $call_data (required)
hashref of call_data that will be turned into xml.
=cut
sub prepare {
my $self = shift;
$self->{verb} = shift;
$self->{call_data} = shift;
if ( ! defined $self->{verb} || ! defined $self->{call_data} ) {
die "missing verb and call_data";
}
# make sure we have appid, devid, certid, token
$self->_load_credentials();
}
=head1 BASECLASS METHODS
=head2 request_agent
Accessor for the LWP::UserAgent request agent
=head2 request_object
Accessor for the HTTP::Request request object
=head2 request_content
Accessor for the complete request body from the HTTP::Request object
=head2 response_content
Accessor for the HTTP response body content
=head2 response_object
Accessor for the HTTP::Request response object
=head2 response_dom
Accessor for the LibXML response DOM
=head2 response_hash
Accessor for the hashified response content
=head2 nodeContent( $tag, [ $dom ] )
Helper for LibXML that retrieves node content
=head2 errors
Accessor to the hashref of errors
=head2 has_error
Returns true if the call contains errors
=head2 errors_as_string
Returns a string of API errors if there are any.
=head1 PRIVATE METHODS
=head2 _validate_response
This is called from the base class. The method is suppose to provide the
custom validation code and push to the error stack if the response isn't
valid
=cut
sub _validate_response {
my $self = shift;
if ( $self->nodeContent('Ack') eq 'Failure' ) {
$self->errors_append( {
'Call Failure' => $self->nodeContent('LongMessage')
} );
}
}
=head2 _get_request_body
This method supplies the request body for the Shopping API call
=cut
sub _get_request_body {
my $self = shift;
# if auth_method is set to 'token' use token
# if auth_method is set to 'iaftoken' use iaftoken
# if auth_method is set to 'user' use username/password
if ( $self->{auth_method} eq 'token' ) {
my $xml = "<?xml version='1.0' encoding='utf-8'?>"
. "<" . $self->{verb} . "Request xmlns=\"urn:ebay:apis:eBLBaseComponents\">"
. "<RequesterCredentials><eBayAuthToken>"
. ( $self->api_config->{token} || '' )
. "</eBayAuthToken></RequesterCredentials>"
. XMLout(
$self->{call_data},
NoAttr => !$self->api_config->{enable_attributes},
KeepRoot => 1,
RootName => undef
)
. "</" . $self->{verb} . "Request>";
return $xml;
}
elsif ( $self->{auth_method} eq 'iaftoken' ) {
my $xml = "<?xml version='1.0' encoding='utf-8'?>"
. "<" . $self->{verb} . "Request xmlns=\"urn:ebay:apis:eBLBaseComponents\">"
. XMLout(
$self->{call_data},
NoAttr => !$self->api_config->{enable_attributes},
KeepRoot => 1,
RootName => undef
)
. "</" . $self->{verb} . "Request>";
return $xml;
}
elsif ( $self->{auth_method} eq 'user' ) {
my $xml = "<?xml version='1.0' encoding='utf-8'?>"
. "<" . $self->{verb} . "Request xmlns=\"urn:ebay:apis:eBLBaseComponents\">"
. "<RequesterCredentials><Username>"
. $self->api_config->{username} . "</Username>";
if ( $self->api_config->{password} ) {
$xml .= "<Password>"
. $self->api_config->{password} . "</Password>";
}
$xml .= "</RequesterCredentials>"
. XMLout( $self->{call_data}, NoAttr => 1, KeepRoot => 1, RootName => undef )
. "</" . $self->{verb} . "Request>";
return $xml;
}
}
=head2 _get_request_headers
This method supplies the headers for the Shopping API call
=cut
sub _get_request_headers {
my $self = shift;
my $obj = HTTP::Headers->new();
$obj->push_header("X-EBAY-API-COMPATIBILITY-LEVEL" =>
$self->api_config->{version});
$obj->push_header("X-EBAY-API-DEV-NAME" => $self->api_config->{devid});
$obj->push_header("X-EBAY-API-APP-NAME" => $self->api_config->{appid});
$obj->push_header("X-EBAY-API-CERT-NAME" => $self->api_config->{certid});
$obj->push_header("X-EBAY-API-SITEID" => $self->api_config->{siteid});
$obj->push_header("X-EBAY-API-CALL-NAME" => $self->{verb});
if ( $self->{auth_method} eq 'iaftoken' ) {
$obj->push_header("X-EBAY-API-IAF-TOKEN" => $self->api_config->{iaftoken});
}
$obj->push_header("Content-Type" => "text/xml");
return $obj;
}
=head2 _get_request_object
This method creates the request object and returns to the parent class
=cut
sub _get_request_object {
my $self = shift;
my $url = sprintf( 'http%s://%s%s',
( $self->api_config->{https} ? 's' : '' ),
$self->api_config->{domain},
$self->api_config->{uri}
);
my $request_obj = HTTP::Request->new(
"POST",
$url,
$self->_get_request_headers,
$self->_get_request_body
);
return $request_obj;
}
sub _load_credentials {
my $self = shift;
# we only need to load credentials once
return if $self->{_credentials_loaded};
my @missing;
# required by the API
for my $reqd ( qw/devid appid certid/ ) {
next if defined $self->api_config->{$reqd};
if ( defined (my $val = $self->_fish_ebay_ini( $reqd )) ) {
$self->api_config->{$reqd} = $val;
}
else {
push( @missing, $reqd );
}
}
if ( scalar @missing > 0 ) {
die "missing Authentication: " . join( ", ", @missing );
}
# Collect token, iaftoken, username, password, domain, https, uri and version from
# the ebay.ini file
# if token found, set auth_method to 'token'
# if iaftoken found, set auth_method to 'iaftoken'
# if username/password found set auth_method to 'user'
for my $optional ( qw/token iaftoken username password domain https uri version/ ) {
next if defined $self->api_config->{$optional};
if ( defined ( my $val = $self->_fish_ebay_ini( $optional )) ) {
$self->api_config->{$optional} = $val;
}
else {
print STDERR "Not defined : " . $optional . "\n" if $DEBUG;
}
}
if ( exists ( $self->api_config->{token} ) ) {
$self->{auth_method} = 'token';
delete($self->api_config->{iaftoken});
delete($self->api_config->{username});
delete($self->api_config->{password});
}
elsif ( exists ( $self->api_config->{iaftoken} ) ) {
$self->{auth_method} = 'iaftoken';
delete($self->api_config->{username});
delete($self->api_config->{password});
}
elsif ((exists( $self->api_config->{username} ))
&& (exists( $self->api_config->{password} ))) {
$self->{auth_method} = 'user';
}
elsif ( exists( $self->api_config->{username} ) ) {
$self->{auth_method} = 'user';
}
else {
die "missing Authentication : token or username/password \n";
}
$self->{_credentials_loaded} = 1;
return;
}
sub _fish_ebay_ini {
my $self = shift;
my $arg = shift;
my @files;
# initialize our hashref
$self->{_ebay_ini} ||= {};
# revert eBay::API::Simple keys to standard keys
$arg = 'DeveloperKey' if $arg eq 'devid';
$arg = 'ApplicationKey' if $arg eq 'appid';
$arg = 'CertificateKey' if $arg eq 'certid';
$arg = 'Token' if $arg eq 'token';
$arg = 'IAFToken' if $arg eq 'iaftoken';
$arg = 'UserName' if $arg eq 'username';
$arg = 'Password' if $arg eq 'password';
$arg = 'Domain' if $arg eq 'domain';
$arg = 'Https' if $arg eq 'https';
$arg = 'Uri' if $arg eq 'uri';
$arg = 'Version' if $arg eq 'version';
# return it if we've already found it
return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
# ini files in order of importance
# Make exception for windows
if ( $^O eq 'MSWin32' ) {
@files = ( './ebay.ini', './ebay.yaml' );
}
else {
@files = (
'./ebay.yaml',
"$ENV{HOME}/ebay.yaml",
'/etc/ebay.yaml',
'./ebay.ini',
"$ENV{HOME}/ebay.ini",
'/etc/ebay.ini',
);
}
foreach my $file ( reverse @files ) {
if ( open( FILE, "<", $file ) ) {
while ( my $line = <FILE> ) {
chomp( $line );
next if $line =~ m!^\s*\#!;
my( $k, $v ) = split( /=/, $line );
if ( defined $k && defined $v) {
$v =~ s/^\s+//;
$v =~ s/\s+$//;
$self->{_ebay_ini}{$k} = $v;
}
}
close FILE;
}
}
return $self->{_ebay_ini}{$arg} if defined $self->{_ebay_ini}{$arg};
return undef;
}
1;
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=head1 CONTRIBUTORS
Jyothi Krishnan
=cut
lib/eBay/API/SimpleBase.pm view on Meta::CPAN
package eBay::API::SimpleBase;
use strict;
use warnings;
use XML::LibXML;
use XML::Simple;
use HTTP::Request;
use HTTP::Headers;
use LWP::UserAgent;
use XML::Parser;
use URI::Escape;
use YAML;
use utf8;
use base 'eBay::API::Simple';
# set the preferred xml simple parser
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
our $DEBUG = 0;
=head1 NAME
eBay::API::SimpleBase - Flexible SDK supporting all eBay web services
=head1 DESCRIPTION
This is the base class for the eBay::API::Simple::* libraries that provide
support for all of eBay's web services. This base class does nothing by itself
and must be subclassed to provide the complete web service support.
=item L<eBay::API::Simple::Merchandising>
=item L<eBay::API::Simple::Finding>
=item L<eBay::API::Simple::Shopping>
=item L<eBay::API::Simple::Trading>
=item L<eBay::API::Simple::HTML>
=item L<eBay::API::Simple::JSON>
=item L<eBay::API::Simple::RSS>
=head1 GET THE SOURCE
http://code.google.com/p/ebay-api-simple
=head1 PUBLIC METHODS
=head2 eBay::API::Simple::{subclass}->new()
see subclass for more docs.
=item L<eBay::API::Simple::Merchandising>
=item L<eBay::API::Simple::Finding>
=item L<eBay::API::Simple::Shopping>
=item L<eBay::API::Simple::Trading>
=item L<eBay::API::Simple::HTML>
=item L<eBay::API::Simple::JSON>
=item L<eBay::API::Simple::RSS>
=cut
sub new {
my $class = shift;
my $api_args = shift;
my $self = {};
bless( $self, $class );
# set some defaults
$self->api_config->{siteid} = 0;
$self->api_config->{enable_attributes} = 0;
$self->api_config->{timeout} = 20 unless defined $api_args->{timeout};
$self->api_config->{parallel} = $api_args->{parallel};
unless (defined $api_args->{preserve_namespace}) {
$self->api_config->{preserve_namespace} = 0;
}
# set the config args
$self->api_config_append( $api_args );
return $self;
}
=head2 execute( $verb, $call_data )
Calling this method will prepare the request, execute, and process the response.
It is recommended that prepare and process be subclassed rather than this method.
=item $verb (required)
call verb, i.e. FindItems
=item $call_data (required)
hashref of call_data that will be turned into xml.
=cut
sub execute {
my $self = shift;
$self->prepare( @_ );
$self->_execute_http_request();
if ( defined $self->{response_content} ) {
$self->process();
}
}
=head2 prepare( $verb, $call_data )
This is called by execute to prepare the request
and may be supplied by the subclass.
=cut
sub prepare {
my $self = shift;
$self->{verb} = shift;
$self->{call_data} = shift;
if ( ! defined $self->{verb} || ! defined $self->{call_data} ) {
die "missing verb and call_data";
}
}
=head2 process()
This is called by execute to process the response
and may be supplied by the subclass.
=cut
sub process {
my $self = shift;
if ( $DEBUG ) {
print STDERR $self->request_object->as_string();
print STDERR $self->response_object->as_string();
}
}
=head2 request_agent
Accessor for the LWP::UserAgent request agent
=cut
sub request_agent {
my $self = shift;
return $self->{request_agent};
}
=head2 request_object
Accessor for the HTTP::Request request object
=cut
sub request_object {
my $self = shift;
return $self->{request_object};
}
=head2 request_content
Accessor for the complete request body from the HTTP::Request object
=cut
sub request_content {
my $self = shift;
return $self->{request_object}->as_string();
}
=head2 response_content
Accessor for the HTTP response body content
=cut
sub response_content {
my $self = shift;
return $self->{response_content};
}
=head2 response_object
Accessor for the HTTP::Request response object
=cut
sub response_object {
my $self = shift;
return $self->{response_object};
}
=head2 response_dom
Accessor for the LibXML response DOM
=cut
sub response_dom {
my $self = shift;
if ( ! defined $self->{response_dom} ) {
my $parser = XML::LibXML->new();
eval {
$self->{response_dom} =
$parser->parse_string( $self->response_content );
};
if ( $@ ) {
$self->errors_append( { 'parsing_error' => $@ } );
}
}
return $self->{response_dom};
}
=head2 response_hash
Accessor for the hashified response content
=cut
sub response_hash {
my $self = shift;
if ( ! defined $self->{response_hash} ) {
$self->{response_hash} = XMLin( $self->response_content,
forcearray => [],
keyattr => []
);
}
return $self->{response_hash};
}
=head2 response_json
Not implemented yet.
=cut
sub response_json {
my $self = shift;
if ( ! defined $self->{response_json} ) {
$self->{response_json} = ''; # xml2json( $self->{response_content} );
}
return $self->{response_json};
}
=head2 nodeContent( $tag, [ $dom ] )
Helper for LibXML that retrieves node content
=item $tag (required)
This is the name of the xml element
=item $dom (optional)
optionally a DOM object can be passed in. If no DOM object
is passed then the main response DOM object is used.
=cut
sub nodeContent {
my $self = shift;
my $tag = shift;
my $node = shift;
$node ||= $self->response_dom();
return if ! $tag || ! $node;
my $e = $node->getElementsByTagName($tag);
if ( defined $e->[0] ) {
return $e->[0]->textContent();
}
else {
#print STDERR "no info for $tag\n";
return;
}
}
=head2 errors
Accessor to the hashref of errors
=cut
sub errors {
my $self = shift;
$self->{errors} = {} unless defined $self->{errors};
return $self->{errors};
}
=head2 has_error
Returns true if the call contains errors
=cut
sub has_error {
my $self = shift;
my $has_error = (keys( %{ $self->errors } ) > 0) ? 1 : 0;
return $has_error;
}
=head2 errors_as_string
Returns a string of API errors if there are any.
=cut
sub errors_as_string {
my $self = shift;
my @e;
for my $k ( keys %{ $self->errors } ) {
push( @e, $k . '-' . $self->errors->{$k} );
}
return join( "\n", @e );
}
=head1 INTERNAL METHODS
=head2 api_config
Accessor to a hashref of api config data that will be used to execute
the api call.
siteid,domain,uri,etc.
=cut
sub api_config {
my $self = shift;
$self->{api_config} = {} unless defined $self->{api_config};
return $self->{api_config};
}
=head2 api_config_append( $hashref )
This method is used to merge config into the config_api hash
=cut
sub api_config_append {
my $self = shift;
my $config_hash = shift;
for my $k ( keys %{ $config_hash } ) {
$self->api_config->{$k} = $config_hash->{$k};
}
}
=head2 api_config_dump()
This method is used for debugging
=cut
sub api_config_dump {
my $self = shift;
my $str;
while ( my( $key, $value ) = each( %{ $self->api_config } ) ) {
$str .= sprintf( "%s=%s\n", $key, $value );
}
return $str;
}
=head2 errors_append
This method lets you append errors to the errors stack
=cut
sub errors_append {
my $self = shift;
my $hashref = shift;
for my $k ( keys %{ $hashref } ) {
$self->errors->{$k} = $hashref->{$k};
}
}
=head1 PRIVATE METHODS
=head2 _execute_http_request
This method performs the http request and should be used by
each subclass.
=cut
sub _execute_http_request {
my $self = shift;
# clear previous call data
$self->_reset();
unless ( defined $self->{request_agent} ) {
$self->{request_agent} = $self->_get_request_agent();
}
unless ( defined $self->{request_object} ) {
$self->{request_object} = $self->_get_request_object();
}
if ( defined $self->api_config->{parallel} ) {
$self->{request_object}->{_ebay_api_simple_instance} = $self;
$self->api_config->{parallel}->register( $self->{request_object} );
return undef;
}
my $max_tries = 1;
if ( defined $self->api_config->{retry} ) {
$max_tries = $self->api_config->{retry} + 1;
}
my $content = '';
my $error = '';
my $response;
for ( my $i=0; $i < $max_tries; ++$i ) {
$response = $self->{request_agent}->request( $self->{request_object} );
if ( $response->is_success ) {
last; # exit the loop
}
}
$self->_process_http_request( $response );
return $self->{response_content};
}
=head2 _process_http_request
This method processes the http request after it has completed.
=cut
sub _process_http_request {
my $self = shift;
my $response = shift;
$self->{response_object} = $response;
if ( $response->is_success ) {
my $content = $response->content();
unless ($self->api_config->{preserve_namespace}) {
# strip out the namespace param, with single or double quotes
$content =~ s/xmlns=("[^"]+"|'[^']+') *//;
}
$self->{response_content} = $content;
# call the classes validate response method if it exists
$self->_validate_response() if $self->can('_validate_response');
}
else {
# store the error
my $error = $response->status_line;
$self->errors_append( { http_response => $error } ) if defined $error;
my $content = $response->content();
$self->{response_content} = $content;
}
}
=head2 _reset
Upon execute() we need to undef any data from a previous call. This
method will clear all call data and is usually done before each execute
=cut
sub _reset {
my $self = shift;
# clear previous call
$self->{errors} = undef;
$self->{response_object} = undef;
$self->{response_content} = undef;
$self->{request_agent} = undef;
$self->{request_object} = undef;
$self->{response_dom} = undef;
$self->{response_json} = undef;
$self->{response_hash} = undef;
}
=head2 _build_url( $base_url, $%params )
Constructs a URL based on the supplied args
=cut
sub _build_url {
my $self = shift;
my $base = shift;
my $args = shift;
my @p;
for my $k ( sort keys %{ $args } ) {
if ( ref( $args->{$k} ) eq 'ARRAY' ) {
for my $ap ( @{ $args->{$k} } ) {
push( @p,
( $k . '=' . uri_escape_utf8( $ap ) )
);
}
}
else {
push( @p, ( $k . '=' . uri_escape_utf8( $args->{$k} ) ) );
}
}
return( scalar( @p ) > 0 ? $base . '?' . join('&', @p) : $base );
}
=head2 _get_request_body
The request body should be provided by the subclass
=cut
sub _get_request_body {
my $self = shift;
my $xml = "<sample>some content</sample>";
return $xml;
}
=head2 _get_request_headers
The request headers should be provided by the subclass
=cut
sub _get_request_headers {
my $self = shift;
my $obj = HTTP::Headers->new();
$obj->push_header("SAMPLE-HEADER" => 'foo');
return $obj;
}
=head2 _get_request_agent
The request request agent should be used by all subclasses
=cut
sub _get_request_agent {
my $self = shift;
my $ua= LWP::UserAgent->new();
$ua->agent( sprintf( '%s / eBay API Simple (Version: %s)',
$ua->agent,
$eBay::API::Simple::VERSION,
) );
# timeout in seconds
if ( defined $self->api_config->{timeout} ) {
$ua->timeout( $self->api_config->{timeout} );
}
# add proxy
if ( $self->api_config->{http_proxy} ) {
$ua->proxy( ['http'], $self->api_config->{http_proxy} );
}
if ( $self->api_config->{https_proxy} ) {
$ua->proxy( ['https'], $self->api_config->{https_proxy} );
}
return $ua;
}
=head2 _get_request_object
The request object should be provided by the subclass
=cut
sub _get_request_object {
my $self = shift;
my $url = sprintf( 'http%s://%s%s',
( $self->api_config->{https} ? 's' : '' ),
$self->api_config->{domain},
$self->api_config->{uri}
);
my $objRequest = HTTP::Request->new(
"POST",
$url,
$self->_get_request_headers,
$self->_get_request_body
);
if( $self->api_config->{authorization_basic}{enabled} ) {
$objRequest->authorization_basic(
$self->api_config->{authorization_basic}{username},
$self->api_config->{authorization_basic}{password}
);
}
return $objRequest;
}
sub authorization_basic {
my $self = shift;
my $username = shift;
my $password = shift;
$self->api_config->{authorization_basic}{username} = $username;
$self->api_config->{authorization_basic}{password} = $password;
$self->api_config->{authorization_basic}{enabled} = 1;
}
sub disable_authorization_basic {
my $self = shift;
$self->api_config->{authorization_basic}{enabled} = 0;
}
=head2 _load_yaml_defaults
This method will search for the ebay.yaml file and load configuration defaults
for each service endpoint
YAML files can be placed at the below locations. The first file found will
be loaded.
./ebay.yaml, ~/ebay.yaml, /etc/ebay.yaml
Sample YAML:
# Trading - External
api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
token: <token>
# Shopping
open.api.ebay.com:
appid: <your appid>
certid: <your certid>
devid: <your devid>
version: 671
# Finding/Merchandising
svcs.ebay.com:
appid: <your appid>
version: 1.0.0
=cut
sub _load_yaml_defaults {
my $self = shift;
return 1 if $self->{_yaml_loaded};
my @files = (
"./ebay.yaml",
"/etc/ebay.yaml",
);
push(@files, "$ENV{HOME}/ebay.yaml") if defined ($ENV{HOME});
foreach my $file ( reverse @files ) {
if ( open( FILE, "<", $file ) ) {
my $yaml;
{
local $/ = undef;
$yaml = <FILE>;
}
my $hashref = YAML::Load($yaml);
my $domain = $self->api_config->{domain};
if ( defined $hashref->{ $domain } ) {
$self->api_config_append( $hashref->{ $domain } );
}
$self->{_yaml_loaded} = 1;
close FILE;
last;
}
}
}
1;
=head1 AUTHOR
Tim Keefer <tim@timkeefer.com>
=head1 CONTRIBUTOR
Andrew Dittes <adittes@gmail.com>
Brian Gontowski <bgontowski@gmail.com>
=cut
use strict;
use warnings;
use lib qw(lib);
use Test::More tests => 8;
use_ok( 'eBay::API::Simple' );
use_ok( 'eBay::API::SimpleBase' );
use_ok( 'eBay::API::Simple::Trading' );
use_ok( 'eBay::API::Simple::Finding' );
use_ok( 'eBay::API::Simple::Shopping' );
use_ok( 'eBay::API::Simple::HTML' );
use_ok( 'eBay::API::Simple::RSS' );
use_ok( 'eBay::API::Simple::JSON' );