I *almost* got my simple eBay API test script working, but I can't seem
to figure out how to set the SOAP header with the RequesterCredentials
object.
With wsdl4ruby.rb, I generated the client classes for the eBay API.
Here's what I got:
---[CUT]---
#!/usr/bin/env ruby
require 'defaultDriver.rb'
callName = "GeteBayOfficialTime"
siteId = "0"
appId = "__MYAPPID__"
devId = "__MYDEVID__"
certId = "__MYCERTID__"
version = "433"
authToken = "__MYAUTHTOKEN__"
endpoint_url = 'https://api.sandbox.ebay.com/wsapi'
request_url = endpoint_url + '?callname=' + callName +
'&siteid=' + siteId +
'&appId=' + appId +
'&version=' + version +
'&routing=default'
service = EBayAPIInterface.new(endpoint_url)
# Uncomment to see wiredumps
service.wiredump_dev = STDERR
RequesterCredentials = CustomSecurityHeaderType.new(authToken)
RequesterCredentials.credentials = UserIdPasswordType.new(appId, devId,
certId)
# Guess... but doesn't work
# service.RequesterCredentials << RequesterCredentials
request = GeteBayOfficialTimeRequestType.new()
request.version = version
response = service.geteBayOfficialTime(request)
---[/CUT]---
OK, see where it says "Guess... but doesn't work" -- my futile attempt
to guess how to add the RequesterCredentials object to the SOAP header.
I tried some variants, but from looking at the generated classes, it
seems there is no 'RequesterCredentials' attribute, even though it is
in the WSDL file:
http://developer.ebay.com/webservices/433/ebaySvc.wsdl
Am I missing something simple?
Thanks, that code got me started writing my own header handler. Here's
my code as it stands now:
---[CUT]---
#!/usr/bin/env ruby
require 'defaultDriver.rb'
require 'soap/header/simplehandler'
class RequesterCredentialsHandler < SOAP::Header::SimpleHandler
HeaderName = XSD::QName.new('urn:ebay:api:eBLBaseComponents',
'RequesterCredentials')
Credentials = XSD::QName.new('urn:ebay:apis:eBLBaseComponents',
'Credentials')
EbayAuthToken = XSD::QName.new(nil, 'eBayAuthToken')
DevId = XSD::QName.new(nil, 'DevId')
AppId = XSD::QName.new(nil, 'AppId')
AuthCert = XSD::QName.new(nil, 'AuthCert')
def initialize(eBayAuthToken, devId, appId, authCert)
super(HeaderName)
@token, @devId, @appId, @cert = eBayAuthToken, devId, appId,
authCert
end
def on_simple_outbound
{ EbayAuthToken => @token,
Credentials => { DevId => @devId, AppId => @appId, AuthCert =>
@cert } }
end
end
callName = "GeteBayOfficialTime"
siteId = "0"
appId = "__myAppId__"
devId = "__myDevId__"
certId = "__myCertId__"
version = "433"
authToken = "__myAuthToken__"
endpoint_url = 'https://api.sandbox.ebay.com/wsapi'
request_url = endpoint_url + '?callname=' + callName +
'&siteid=' + siteId +
'&appId=' + appId +
'&version=' + version +
'&routing=default'
service = EBayAPIInterface.new(endpoint_url)
# Uncomment to see wiredumps
service.wiredump_dev = STDOUT
RequesterCredentials = RequesterCredentialsHandler.new(authToken,
devId, appId, certId)
service.headerhandler << RequesterCredentials
request = GeteBayOfficialTimeRequestType.new()
request.version = version
response = service.geteBayOfficialTime(request)
---[CUT]---
The output is:
[garry@cvs ebay_soap_ruby]$ ./gg.rb
Wire dump:
opening connection to api.sandbox.ebay.com...
opened
warning: peer certificate won't be verified in this SSL session
<- "POST /wsapi HTTP/1.1\r\nAccept: */*\r\nContent-Type: text/xml;
charset=utf-8\r\nUser-Agent: SOAP4R/1.5.5\r\nSoapaction:
\"\"\r\nContent-Length: 853\r\nHost: api.sandbox.ebay.com\r\n\r\n"
<- "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<env:Envelope
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n
xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\"\n
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n
<env:Header>\n <RequesterCredentials
xmlns:n1=\"urn:ebay:apis:eBLBaseComponents\"\n
env:mustUnderstand=\"0\"\n
xmlns=\"urn:ebay:api:eBLBaseComponents\">\n <n1:Credentials>\n
<DevId>__myDevId__</DevId>\n
<AppId>__myAppId__</AppId>\n
<AuthCert>__myCertId__</AuthCert>\n </n1:Credentials>\n
<eBayAuthToken>__myAuthToken__</eBayAuthToken>\n
</RequesterCredentials>\n </env:Header>\n <env:Body>\n
<GeteBayOfficialTimeRequest
xmlns=\"urn:ebay:apis:eBLBaseComponents\">\n
<Version>433</Version>\n </GeteBayOfficialTimeRequest>\n
</env:Body>\n</env:Envelope>"
-> "HTTP/1.1 500 Internal Server Error\r\n"
-> "Date: Tue, 08 Nov 2005 09:54:06 GMT\r\n"
-> "Server: Microsoft-IIS/5.0\r\n"
-> "Content-Type: text/xml; charset=utf-8\r\n"
-> "X-EBAY-API-SERVER-NAME: um.s5tad671*77-3(6:7(46?>7;4\r\n"
-> "Content-Language: en\r\n"
-> "X-Cache: MISS from thrasher.sjc.ebay.com\r\n"
-> "Connection: close\r\n"
-> "Transfer-Encoding: chunked\r\n"
-> "\r\n"
-> "222\r\n"
reading 546 bytes...
-> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<soapenv:Envelope
xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n
<soapenv:Body>\n <soapenv:Fault>\n
<faultcode>soapenv:Server.userException</faultcode>\n
<faultstring>com.ebay.app.pres.service.hosting.WebServiceDisabledException:
The web service eBayAPI is not properly configured or not found and is
disabled.</faultstring>\n <detail/>\n </soapenv:Fault>\n
</soapenv:Body>\n</soapenv:Envelope>"
read 546 bytes
reading 2 bytes...
-> "\r\n"
read 2 bytes
-> "0\r\n"
-> "\r\n"
Conn close
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server.userException</faultcode>
<faultstring>com.ebay.app.pres.service.hosting.WebServiceDisabledException:
The web service eBayAPI is not properly configured or not found and is
disabled.</faultstring>
<detail/>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
#<SOAP::Mapping::Object:0x4059acf0>:
com.ebay.app.pres.service.hosting.WebServiceDisabledException: The web
service eBayAPI is not properly configured or not found and is
disabled. (SOAP::FaultError)
---[CUT]---
As you can see, eBay didn't like it.
What I wonder is, why do I see, for example, "<n1:Credentials>" in the
wire dump, instead of "<ns:Credentials>" (which is what it should be)?
For reference, from eBay's documentation, the SOAP Message Request
should look like:
---[CUT]---
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<RequesterCredentials soapenv:mustUnderstand="0"
xmlns="urn:ebay:apis:eBLBaseComponents">
<eBayAuthToken>__myAuthToken__</eBayAuthToken>
<ns:Credentials xmlns:ns="urn:ebay:apis:eBLBaseComponents">
<ns:DevId>__myDevId__</ns:DevId>
<ns:AppId>__myAppId__</ns:AppId>
<ns:AuthCert>__myAuthCert__</ns:AuthCert>
</ns:Credentials>
</RequesterCredentials>
</soapenv:Header>
<soapenv:Body>
<GeteBayOfficialTimeRequest
xmlns="urn:ebay:apis:eBLBaseComponents">
<ns1:Version
xmlns:ns1="urn:ebay:apis:eBLBaseComponents">433</ns1:Version>
</GeteBayOfficialTimeRequest>
</soapenv:Body>
</soapenv:Envelope>
---[CUT]---
The output I have is close, but not exactly the same. I think this is
why eBay is not returning the proper output. The output should be:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<GeteBayOfficialTimeResponse
xmlns="urn:ebay:apis:eBLBaseComponents">
<Timestamp>2005-05-02T00:07:22.895Z</Timestamp>
<Ack>Success</Ack>
<CorrelationID>
00000000-00000000-00000000-00000000-00000000-00000000-0000000000
</CorrelationID>
<Version>433</Version>
<Build>20050422132524</Build>
</GeteBayOfficialTimeResponse>
</soapenv:Body>
</soapenv:Envelope>
Ideas anyone?
I don't think authentication is a problem because that actually
generates a different error (and I can use all the same values for
AuthToken, AppId, etc... in PHP, and it works).
I'm new to XML, so please excuse the naive question:
"<ns:Credentials>" and "<n1:Credentials>" mean the same thing?
Stupid me, I found a bug where it reads:
service = EBayAPIInterface.new(endpoint_url)
should be:
service = EBayAPIInterface.new(request_url)
So I made that change, and also got the header to re-order the elements
(in the proper order).
Says something is wrong with my header, but at least I get a better
response:
Wire dump:
opening connection to api.sandbox.ebay.com...
opened
warning: peer certificate won't be verified in this SSL session
<- "POST
/wsapi?callname=GeteBayOfficialTime&siteid=0&appid=__myAppId__&version=433&routing=default
HTTP/1.1\r\nAccept: */*\r\nContent-Type: text/xml;
charset=utf-8\r\nUser-Agent: SOAP4R/1.5.5\r\nSoapaction:
\"\"\r\nContent-Length: 1766\r\nHost: api.sandbox.ebay.com\r\n\r\n"
<- "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<env:Envelope
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n
xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\"\n
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n
<env:Header>\n <RequesterCredentials
xmlns:n1=\"urn:ebay:apis:eBLBaseComponents\"\n
env:mustUnderstand=\"0\"\n
xmlns=\"urn:ebay:api:eBLBaseComponents\">\n
<eBayAuthToken>blah...</eBayAuthToken>\n <n1:Credentials>\n
<DevId>blah...</DevId>\n <AppId>blah...</AppId>\n
<AuthCert>blah..</AuthCert>\n </n1:Credentials>\n
</RequesterCredentials>\n </env:Header>\n <env:Body>\n
<GeteBayOfficialTimeRequest
xmlns=\"urn:ebay:apis:eBLBaseComponents\">\n
<Version>433</Version>\n </GeteBayOfficialTimeRequest>\n
</env:Body>\n</env:Envelope>"
-> "HTTP/1.1 500 Internal Server Error\r\n"
-> "Date: Wed, 09 Nov 2005 02:21:32 GMT\r\n"
-> "Server: Microsoft-IIS/5.0\r\n"
-> "Content-Type: text/xml; charset=utf-8\r\n"
-> "X-EBAY-API-SERVER-NAME: um.s5tadvn357(25(1-4?5-05=;5>7\r\n"
-> "Content-Language: en\r\n"
-> "X-Cache: MISS from thrasher.sjc.ebay.com\r\n"
-> "Connection: close\r\n"
-> "Transfer-Encoding: chunked\r\n"
-> "\r\n"
-> "2f5\r\n"
reading 757 bytes...
-> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<soapenv:Envelope
xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n
<soapenv:Body>\n <soapenv:Fault>\n <faultcode
xmlns:ns1=\"http://xml.apache.org/axis/\">ns1:FailedAuthentication</faultcode>\n
<faultstring>SOAP Authentication failed.</faultstring>\n
<faultactor>http://www.ebay.com/ws/websvc/eBayAPI</faultactor>\n
<detail>\n <FaultDetail>\n <ErrorCode>14007</ErrorCode>\n
<Severity>Error</Severity>\n <DetailedMessage>SOAP Authentication
failed due to missing or invalid security header.</DetailedMessage>\n
</FaultDetail>\n </detail>\n </soape"
-> "nv:Fault>\n </soapenv:Body>\n</soapenv:Envelope>"
read 757 bytes
reading 2 bytes...
-> "\r\n"
read 2 bytes
-> "0\r\n"
-> "\r\n"
Conn close
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<soapenv:Fault>
<faultcode
xmlns:ns1="http://xml.apache.org/axis/">ns1:FailedAuthentication</faultcode>
<faultstring>SOAP Authentication failed.</faultstring>
<faultactor>http://www.ebay.com/ws/websvc/eBayAPI</faultactor>
<detail>
<FaultDetail>
<ErrorCode>14007</ErrorCode>
<Severity>Error</Severity>
<DetailedMessage>SOAP Authentication failed due to missing or
invalid security header.</DetailedMessage>
</FaultDetail>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
#<SOAP::Mapping::Object:0x405966f0>: SOAP Authentication failed.
(SOAP::FaultError)
Note, I deleted my real Token and stuff from the above output.
I still get a header error, any ideas anyone?
OK, once again, I'm stupid, the line that reads:
HeaderName = XSD::QName.new('urn:ebay:api:eBLBaseComponents',
'RequesterCredentials')
Should have been:
HeaderName = XSD::QName.new('urn:ebay:apis:eBLBaseComponents',
'RequesterCredentials')
One letter off (can u find it? ;)
So now my interface to eBay works. For everyone's reference, here's
how I called the GeteBayOfficialTime function w/ SOAP + ruby:
--[CUT]--
#!/usr/bin/env ruby
require 'defaultDriver.rb'
require 'soap/header/simplehandler'
class RequesterCredentialsHandler < SOAP::Header::SimpleHandler
HeaderName = XSD::QName.new('urn:ebay:apis:eBLBaseComponents',
'RequesterCredentials')
Credentials = XSD::QName.new('urn:ebay:apis:eBLBaseComponents',
'Credentials')
EbayAuthToken = XSD::QName.new(nil, 'eBayAuthToken')
DevId = XSD::QName.new(nil, 'DevId')
AppId = XSD::QName.new(nil, 'AppId')
AuthCert = XSD::QName.new(nil, 'AuthCert')
def initialize(eBayAuthToken, devId, appId, authCert)
super(HeaderName)
@token, @devId, @appId, @cert = eBayAuthToken, devId, appId,
authCert
end
def on_simple_outbound
{ EbayAuthToken => @token,
Credentials => { DevId => @devId, AppId => @appId, AuthCert =>
@cert } }
end
end
callName = 'GeteBayOfficialTime'
siteId = '0'
appId = '__appid__'
devId = '__devid__'
certId = '__certid__'
version = '433'
authToken = '__authtoken__'
endpoint_url = 'https://api.sandbox.ebay.com/wsapi'
request_url = endpoint_url + '?callname=' + callName +
'&siteid=' + siteId +
'&appid=' + appId +
'&version=' + version +
'&routing=default'
service = EBayAPIInterface.new(request_url)
service.headerhandler << RequesterCredentialsHandler.new(authToken,
devId, appId, certId)
request = GeteBayOfficialTimeRequestType.new()
request.version = version
response = service.geteBayOfficialTime(request)
puts response.timestamp
--[CUT]--
Enjoy!
Yes, you may include my sample client. :)
./wsdl2ruby.rb --wsdl
http://developer.ebay.com/webservices/latest/eBaySvc.wsdl --type client
Then download eBaySvc.wsdl to your local box and apply this patch (this
is for the v433 schema):
--[cut]--
--- eBaySvc.wsdl.org 2005-11-07 22:41:23.000000000 +0900
+++ eBaySvc.wsdl 2005-11-07 22:41:06.000000000 +0900
@@ -4579,5 +4579,5 @@ items at once.
</xs:annotation>
<xs:complexContent>
- <xs:extension base="AbstractRequestType">
+ <xs:extension base="ns:AbstractRequestType">
<xs:sequence>
<xs:element name="Sort"
type="ItemSortTypeCodeType" minOccurs="0">
@@ -4619,5 +4619,5 @@ items at once.
</xs:annotation>
<xs:complexContent>
- <xs:extension base="AbstractResponseType">
+ <xs:extension base="ns:AbstractResponseType">
<xs:sequence>
<xs:element
name="ItemsAwaitingFeedback" type="PaginatedTransactionArrayType"
minOccurs="0">
@@ -5212,5 +5212,5 @@ property of the request object.
</xs:annotation>
<xs:complexContent>
- <xs:extension base="AbstractRequestType">
+ <xs:extension base="ns:AbstractRequestType">
<xs:sequence>
<xs:element name="WatchList"
type="ItemListCustomizationType" minOccurs="0">
@@ -5341,5 +5341,5 @@ property of the request object.
</xs:annotation>
<xs:complexContent>
- <xs:extension base="AbstractResponseType">
+ <xs:extension base="ns:AbstractResponseType">
<xs:sequence>
<xs:element
name="BuyingSummary" type="BuyingSummaryType" minOccurs="0">
@@ -5476,5 +5476,5 @@ property of the request object.
</xs:annotation>
<xs:complexContent>
- <xs:extension base="AbstractRequestType">
+ <xs:extension base="ns:AbstractRequestType">
<xs:sequence>
<xs:element
name="BuyingReminders" type="ReminderCustomizationType" minOccurs="0">
@@ -5512,5 +5512,5 @@ property of the request object.
</xs:annotation>
<xs:complexContent>
- <xs:extension base="AbstractResponseType">
+ <xs:extension base="ns:AbstractResponseType">
<xs:sequence>
<xs:element
name="BuyingReminders" type="RemindersType" minOccurs="0">
@@ -5554,5 +5554,5 @@ property of the request object.
</xs:annotation>
<xs:complexContent>
- <xs:extension base="AbstractRequestType">
+ <xs:extension base="ns:AbstractRequestType">
<xs:sequence>
<xs:element
name="ScheduledList" type="ItemListCustomizationType" minOccurs="0">
@@ -5636,5 +5636,5 @@ property of the request object.
</xs:annotation>
<xs:complexContent>
- <xs:extension base="AbstractResponseType">
+ <xs:extension base="ns:AbstractResponseType">
<xs:sequence>
<xs:element
name="SellingSummary" type="SellingSummaryType" minOccurs="0">
--[cut]--
Then this should do it:
./wsdl2ruby.rb --wsdl eBaySvc-433.wsdl --type client
If for some reason this doesn't work for you (or u don't want to bother
with it), I can email you the defaultDriver.rb and default.rb if you
like.