Ruby's soap4r not providing namespace? - ruby

I'm attempting to use soap4r (from https://github.com/mumboe/soap4r) to write a SOAP Client for a product called SysAid.
I have a working example of the SOAP client in Java and, for most methods, my Ruby client works too. The Java client is useful in determining errors with the Ruby version.
I'm receiving an error when I use a particular call:
SOAP::FaultError: prefix xs is not bound to a namespace
Here's the message that soap4r sent, which generated that error:
<?xml version="1.0" encoding="utf-8" ?>
<env:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<n1:save xmlns:n1="http://api.ilient.com/">
<sessionId>1339292997261</sessionId>
<apiSysObj xsi:type="n1:apiServiceRequest">
<customDateFields></customDateFields>
<customFields>
<entry>
<key xsi:type="xs:string">sr_cust_dafis_fau</key>
<value xsi:type="xs:string"></value>
</entry>
<entry>
<key xsi:type="xs:string">sr_cust_activity</key>
</entry>
</customFields>
<description>This is the description of the ticket.</description>
</apiSysObj>
</n1:save>
</env:Body>
</env:Envelope>
And here is what Java sends for the same method, which the server does not complain about:
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:save xmlns:ns2="http://api.ilient.com/">
<sessionId>1339199684324</sessionId>
<apiSysObj xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:apiServiceRequest">
<customDateFields/><customFields>
<entry>
<key xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">sr_cust_dafis_fau</key>
<value xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string"></value>
</entry>
<entry>
<key xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">sr_cust_activity</key>
</entry>
</customFields>
<description>This is the description of the ticket.</description>
</apiSysObj>
</ns2:save>
</S:Body>
</S:Envelope>
As you can see, the error is coming from the customFields tag. soap4r is leaving out the xmlns:xs attribute on the key tag, while Java is putting it in.
soap4r does not make critical errors like this on any other method call as far as I can tell.
How can I get soap4r to add this needed attribute to the key tag?

I think the namespace "xmlns:xsd="http://www.w3.org/2001/XMLSchema" has been defined in the "env:Envelope", the problem is why in the body soap4r uses "xs:string" instead of "xsd:string".

Related

Cannot iterate through results from DSS with ForEach mediator possibly due to namespace

I am having a great deal of difficulty with XPath finding any data in results returned from a DSS service.
This is a sample of the data returned:
<?xml version='1.0' encoding='utf-8'?>
<Entries xmlns="http://ws.wso2.org/dataservice">
<Entry>
<FirstName>Sandra</FirstName>
<LastName>Carr</LastName>
<FlightDate>2016-07-23T18:24:12.000-04:00</FlightDate>
<Duration>2.8</Duration>
<FlightEndTime>2016-07-23T21:24:12.000-04:00</FlightEndTime>
</Entry>
<Entry>
<FirstName>Lawrence</FirstName>
<LastName>Day</LastName>
<FlightDate>2016-07-23T18:02:21.000-04:00</FlightDate>
<Duration>2.8</Duration>
<FlightEndTime>2016-07-23T21:02:21.000-04:00</FlightEndTime>
</Entry>
I have a simple synapse API sequence which is
<?xml version="1.0" encoding="UTF-8"?>
<api context="/pilots" name="GetPilots" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET">
<inSequence>
<call>
<endpoint key="GetPilotsRestEndpoint"/>
</call>
<foreach description="" expression="/Entries/Entry" id="field">
<sequence>
<log description="" level="custom">
<property name="tag" value="Entry"/>
</log>
</sequence>
</foreach>
<log level="full"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
I am not getting any results. I am wondering if it is because of the namespace in the "Entries" tag.
In any case, would someone please help me with how I can iterate through the results?
Thanks.
There are two things here.
1. Your payload has a namespace http://ws.wso2.org/dataservice and you need to add that to your XPath
2. The response from the backend looks like below.
<Entries xmlns="http://ws.wso2.org/dataservice">
<Entry>
<FirstName>Sandra</FirstName>
<LastName>Carr</LastName>
<FlightDate>2016-07-23T18:24:12.000-04:00</FlightDate>
<Duration>2.8</Duration>
<FlightEndTime>2016-07-23T21:24:12.000-04:00</FlightEndTime>
</Entry>
<Entry>
<FirstName>Lawrence</FirstName>
<LastName>Day</LastName>
<FlightDate>2016-07-23T18:02:21.000-04:00</FlightDate>
<Duration>2.8</Duration>
<FlightEndTime>2016-07-23T21:02:21.000-04:00</FlightEndTime>
</Entry>
However, when it reaches ESB, it gets wrapped with SOAP envelope and will look like below. You can verify this by enabling wire logs or adding <log level="full"/> right after call mediator.
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<Entries xmlns="http://ws.wso2.org/dataservice">
<Entry>
<FirstName>Sandra</FirstName>
<LastName>Carr</LastName>
<FlightDate>2016-07-23T18:24:12.000-04:00</FlightDate>
<Duration>2.8</Duration>
<FlightEndTime>2016-07-23T21:24:12.000-04:00</FlightEndTime>
</Entry>
<Entry>
<FirstName>Lawrence</FirstName>
<LastName>Day</LastName>
<FlightDate>2016-07-23T18:02:21.000-04:00</FlightDate>
<Duration>2.8</Duration>
<FlightEndTime>2016-07-23T21:02:21.000-04:00</FlightEndTime>
</Entry>
</Entries>
</soapenv:Body>
</soapenv:Envelope>
Therefore, your XPath /Entries/Entry would not work since the starting element is not Entries but Envelope.
Please use the following configuration (with //) instead where Entries element would be matched wherever it appears in the payload.
<foreach xmlns:ns="http://ws.wso2.org/dataservice" id="field" expression="//ns:Entries/ns:Entry">
Yes, it must be a namespace issue. Try this.
<foreach description="" expression="//ns:Entries/ns:Entry" id="field"
xmlns:ns="http://ws.wso2.org/dataservice">

Ruby Savon: Call SOAP webservice without operation

I need to call a SOAP service that doesn’t contain any operation encapsulation on the body.
Normally with Savon (Ruby 2.3, Savon 2.11) we have:
client = Savon.client(endpoint: 'http://example.com', namespace: 'http://v1.example.com')
response = client.call(:opName, message_hash)
And this will generate a request like:
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="http://v1.example.com" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<wsdl:opName>
...message content ...
</wsdl:opName>
</env:Body>
</env:Envelope>
But I dont want it to generate the <wsdl:opName> node. I tried to passnil as the operation but it generates the tag as <wsdl:>.
I want to generate a SOAP request without it, like:
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="http://v1.example.com" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
...message content ...
</env:Body>
</env:Envelope>

Savon ruby gem adds ins0 to tags

Using the savon gem, I get the following request XML:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="URL"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ins0="SOME URL">
<soap:Body>
<ins0:Test xmlns="SOME URL">
</ins0:Test>
</soap:Body>
</soap:Envelope>
But it needs to be this instead:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="URL"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Test xmlns="SOME URL">
</Test>
</soap:Body>
</soap:Envelope>
Notice ins0 was removed.
Any suggestions?
The two XML documents are equivalent, so there should be no issues as long as the document is parsed by an XML compliant agent.
The Savon generated document is simply creating a namespace prefix of ins0 for the "SOME URL" namespace. This is convenient for a large SOAP document with many elements from that namespace. In this example, the prefix is not really necessary.
The only potential issue I can see is that the Savion generated document seems to declare the ins0 namespace twice - once in the soap:Envelope and then again in the soap:Body. Seems superfluous and potentially open to error.

CleverElements / Sendcockpit SOAP API parameters aren't recognized

I'm trying to use the CleverElements SOAP API, but I can't get it to work. I have honestly never worked with SOAP (but a lot with XML-RPC, REST, etc.), and thought it should be straightforward.
I'm using Ruby with the savon gem. I can call any function via SOAP which doesn't need any parameters, but on functions with parameters, the SOAP service doesn't recognize the parameters.
This is my request:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="Sendcockpit/API" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="Sendcockpit/API">
<env:Header>
<validate>
<userid>32027</userid>
<apikey>**************</apikey>
<version>1.0</version>
<mode>live</mode>
</validate>
</env:Header>
<env:Body>
<apiGetListDetails>
<listID>72472</listID>
</apiGetListDetails>
</env:Body>
</env:Envelope>
This is the WSDL file: http://api.sendcockpit.com/server.php?wsdl
Am I missing something (maybe dead simple, super obvious, basic SOAP) stuff?
Never mind. Apparently I need a wrapping <ctListRequest> node. I was under the impression that savon applies all things specified by the wsdl file...
This request works:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="Sendcockpit/API" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="Sendcockpit/API">
<env:Header>
<validate>
<userid>32027</userid>
<apikey>***********</apikey>
<version>1.0</version>
<mode>live</mode>
</validate>
</env:Header>
<env:Body>
<apiGetListDetails>
<ctListRequest>
<listID>72472</listID>
</ctListRequest>
</apiGetListDetails>
</env:Body>
</env:Envelope>

Example Soap Body for DescribeSObjects call

I'm running into some issues doing a describeSObject call from a ruby on rails application using Savon. Could someone share an example of what my soap body should look like either from past experience with the salesforce partner api or general wsdl knowledge?
Here's what my application is generating:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:wsdl="urn:partner.soap.sforce.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ins0="urn:partner.soap.sforce.com" xmlns:ins1="urn:fault.partner.soap.sforce.com" xmlns:ins2="urn:sobject.partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
<wsdl:SessionHeader>
<wsdl:sessionId>REMOVED</wsdl:sessionId>
</wsdl:SessionHeader>
</env:Header>
<env:Body>
<ins0:describeSObjects>
<wsdl:object1>Action_Plans_Settings__c</wsdl:object1>
<wsdl:object2>QuoteLineSyncField__c</wsdl:object2>
</ins0:describeSObjects>
</env:Body>
</env:Envelope>
I know this isn't correct, but I'm having trouble figuring out from the wsdl alone what the final soap body would look like. I've browsed the salesforce forums and docs without much luck.
Here's the wsdl definition for this operation, perhaps some wsdl gurus can figure this out based on it:
<operation name="describeSObjects">
<documentation>Describe a number sObjects</documentation>
<input message="tns:describeSObjectsRequest"/>
<output message="tns:describeSObjectsResponse"/>
<fault message="tns:InvalidSObjectFault" name="InvalidSObjectFault"/>
<fault message="tns:UnexpectedErrorFault" name="UnexpectedErrorFault"/>
</operation>
<message name="describeSObjectsRequest">
<part element="tns:describeSObjects" name="parameters"/>
</message>
<element name="describeSObjects">
<complexType>
<sequence>
<element name="sObjectType" type="xsd:string" minOccurs='0' maxOccurs='100' />
</sequence>
</complexType>
</element>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:urn="urn:partner.soap.sforce.com">
<soapenv:Header>
<urn:SessionHeader>
<urn:sessionId>someSessionId</urn:sessionId>
</urn:SessionHeader>
</soapenv:Header>
<soapenv:Body>
<urn:describeSObjects>
<urn:sObjectType>Account</urn:sObjectType>
<urn:sObjectType>Contact</urn:sObjectType>
</urn:describeSObjects>
</soapenv:Body>
</soapenv:Envelope>

Resources