Connecting to Web service with Savon - ruby-on-rails

I am trying to connect to a Webservice from Ruby with Savon - it is a SOAP based Webservice. It also requires an x509 cert which I have the keys for but I am trying to bypass this at the minute just to get it working with ssl_verify_mode set to none
client = Savon.client(wsdl: WSDL_URL,
log: true, # set to true to switch on logging
log_level: :debug,
convert_request_keys_to: :camelcase,
pretty_print_xml: true,
ssl_verify_mode: :none)
I have been able to generate my WSDL classes in .NET and hit the Webservice from c# client app.
My C# for the call to GetInformation from client is below
var analysisTypes = new AnalysisType[4];
analysisTypes[0] = AnalysisType.A;
analysisTypes[1] = AnalysisType.B;
analysisTypes[2] = AnalysisType.C;
analysisTypes[3] = AnalysisType.D;
var coord1 = new Coordinate {
Id = i.ToString(),
X = -110.5322,
Y = 35.2108, QualityIndex = 90 };
string ticketId = serviceClient.GetInformationsForCoordinates(
coord1, analysisTypes);
I am new to Ruby however and having difficulty in getting the same generated below to pass to Savon - so far I have got the following:
coordinate = { Id: '1', X: -110.5322, Y: 35.2108, QualityIndex: 90 }
ticket_id = client.call(:get_informations_for_coordinates,
message: coordinate)
print ticket_id
This fails - I can see the SOAP message it sends below:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tns="http://tempuri.org/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<tns:GetInformationsForCoordinates>
<Id>1</Id>
<X>-110.5322</X>
<Y>35.2108</Y>
<QualityIndex>90</QualityIndex>
</tns:GetInformationsForCoordinates>
</env:Body>
</env:Envelope>
If I look at soap UI and click on the GetInformationsForCoordinates I can see how I should build up the SOAP message - what is the best way for me to Build up this type of message in Ruby - should I pass it all as a message and change the coordinate variable to be message?
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:tem="http://tempuri.org/"
xmlns:mun="http://WebService I want to hit"
xmlns:mun1="http://WebService I want to Hit">
<soap:Header/>
<soap:Body>
<tem:GetInformationsForCoordinates>
<!--Optional:-->
<tem:coordReq>
<!--Optional:-->
<mun:Basemap>?</mun:Basemap>
<!--Optional:-->
<mun:GenerateReport>?</mun:GenerateReport>
<!--Optional:-->
<mun:MapsForReport>
<!--Zero or more repetitions:-->
<mun1:HMap>?</mun1:HMap>
</mun:MapsForReport>
<!--Optional:-->
<mun:PortName>?</mun:PortName>
<!--Optional:-->
<mun:Coordinates>
<!--Zero or more repetitions:-->
<mun:Coordinate>
<!--Optional:-->
<mun:Id>?</mun:Id>
<!--Optional:-->
<mun:QualityIndex>?</mun:QualityIndex>
<!--Optional:-->
<mun:X>?</mun:X>
<!--Optional:-->
<mun:Y>?</mun:Y>
</mun:Coordinate>
</mun:Coordinates>
</tem:coordReq>
<!--Optional:-->
<tem:analysisTypes>
<!--Zero or more repetitions:-->
<mun:AnalysisType>?</mun:AnalysisType>
</tem:analysisTypes>
</tem:GetInformationsForCoordinates>
</soap:Body>
</soap:Envelope>

I would avoid complex structures in the SOAP message. That would mean I'd not use an array as parameter. I'm not even sure whether that's supported at all.
You also might want to prefix the elements in your message, eg.:
coordinate = { 'tns:Id' => '1',
'tns:X' => -110.5322,
'tns:Y' => 35.2108,
'tns:QualityIndex' => 90 }
or whichever namespace defines those elements.
To build up a list of paramters one has build a hash for the message. The complete call would look like this (it's not a correct piece of code but it should give you the right direction to follow):
require 'pp'
require 'savon'
client = Savon.client(wsdl: WSDL_URL,
log: true, # set to true to switch on logging
log_level: :debug,
convert_request_keys_to: :camelcase,
pretty_print_xml: true,
ssl_verify_mode: :none)
rc = client.call(:get_informations_for_coordinates,
message: {
coordinates => { 'tns:Id' => '1',
'tns:X' => -110.5322,
'tns:Y' => 35.2108,
'tns:QualityIndex' => 90 },
analysis_types => {
'tns:type0' => 'A',
'tns:type1' => 'B'
}
}
)
pp rc.to_hash

Related

Flutter SOAP: How to using SOAP in Flutter?

How to using SOAP Api calls in Flutter? I have tried rest calls is working fine. I need to build SOAP calls in flutter. Kindly share how to call SOAP in flutter
refer this link sucessfully call SOAP https://dartpad.dartlang.org/2561dd3579e45d1eb730
void functionCall() async {
var envelope = '''
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetAllCity xmlns="http://tempuri.org/" />
</soap:Body>
</soap:Envelope>
''';
http.Response response = await http.post(
'http://www.i2isoftwares.com/SSKSService/sskss.asmx',
headers: {
"Content-Type": "text/xml; charset=utf-8",
"SOAPAction": "http://tempuri.org/GetAllCity",
"Host": "www.i2isoftwares.com"
//"Accept": "text/xml"
},
body: envelope);
var rawXmlResponse = response.body;
// Use the xml package's 'parse' method to parse the response.
xml.XmlDocument parsedXml = xml.parse(rawXmlResponse);
print("DATAResult=" + response.body);
}

How to make this soap request using savon

Could someone explain me how can I use savon to make this soap request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ent="some_adress">
<soapenv:Header>
<ent:providerID>?</ent:providerID>
</soapenv:Header>
<soapenv:Body>
<ent:operationRequest>
<ent:operation>
<!--You may enter the following 2 items in any order-->
<ent:id>operation_id</ent:id>
<ent:params>
<!--1 or more repetitions:-->
<ent:entry>
<ent:key>param1_name</ent:key>
<ent:value>param1_valuee</ent:value>
</ent:entry>
<ent:entry>
<ent:key>param2_name</ent:key>
<ent:value>param2_value</ent:value>
</ent:entry>
</ent:params>
</ent:operation>
</ent:operationRequest>
</soapenv:Body>
</soapenv:Envelope>
This soap request I got in soapUI.
I tried this (not to make a request, but to see how savon will generate the soap request):
test_message = {:param_1_name => 'param 1 value', :param_2_name => 'param 2 value'}
ops = wsdl_client.operation(:request_operation)
ops.build(message: test_message).to_s
And the result was very different from the soapUi 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:ns1="some_adress" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="some_adress">
<env:Header>
<ent:providerID>999</ent:providerID>
</env:Header>
<env:Body>
<ins0:operationRequest>
<ns1:param1Name>param 1 value</ns1:param1Name>
<ns1:param2Name>param 2 value</ns1:param2Name>
</ins0:operationRequest>
</env:Body>
</env:Envelope>
I couldn't figure it out how to add this 'entries' to a savon request.
Thank you gyus!
I find out a way to do it.
request = {
operation: {
id: '123',
params: [
entry: [{
key: 'param1',
value: '9999999'
},
{
key: 'param2',
value: 'ASD'
}]
]
}
}
I wrote this hash and passed it as the message in the call method.
Thanks!

SOAP REQUEST USING Ruby without using any gem

http = Net::HTTP.new('rty.makemytrip.com', 80)
http.use_ssl = false
path="http://rty.makemytrip.com/btd_Webs_CreateIncident/MMT_Webs_CreateIncident.asmx?op=CreateIncident"
# Create the SOAP Envelope
data = <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body>
<CreateIncident xmlns="http://MakeMyTrip.org/">
<FirstName>#{params[:name]}</FirstName>
<Email>#{params[:email]}</Email>
<CityOfResidence>#{params[:city]}</CityOfResidence>
<MobilePhone>#{params[:mobile]}</MobilePhone>
</CreateIncident>
</SOAP:Body>
</SOAP-ENV:Envelope>
EOF
# Set Headers
headers = {
'Content-Type' => 'Content-Type: application/soap+xml; charset=utf-8'
}
# Post the request
resp, data = http.post(path, data, headers)
# Output the results
logger.error "code = >>>>>>>>#{resp.code}"
logger.error "Response message = >>>>>>>>Message =#{resp.message}"
resp.each { |key, val|
logger.error "key>#{key}>>>>>#{val}"
}
logger.error "data>>>>>#{ data}"
it gives us this error
code = >>>>>>>>500
Response message = >>>>>>>>Message =Internal Server Error
key>x-powered-by>>>>>ASP.NET
key>x-aspnet-version>>>>>2.0.50727
key>connection>>>>>close
key>content-type>>>>>text/xml; charset=utf-8
key>date>>>>>Thu, 19 Sep 2013 08:35:13 GMT
key>server>>>>>Microsoft-IIS/7.5
key>content-length>>>>>442
key>cache-control>>>>>private
data>>>>>
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Server was unable to process request. ---> 'SOAP' is an undeclared namespace. Line 8, position 5.</faultstring>
<detail />
</soap:Fault>
</soap:Body>
</soap:Envelope>
what is wrong in this code
The error is 'SOAP' is an undeclared namespace. Line 8, position 5. It complains on this string <SOAP:Body> in your request, because namespace SOAP wasn't declared.
So, you declared SOAP-ENV as namespace for http://schemas.xmlsoap.org/soap/envelope/ and I think it should be changed to <SOAP-ENV:Body>. And don't forget to change </SOAP:Body> to </SOAP-ENV:Body> too.

Creating soap request with http build

Im trying to make a soap request using httpbuilder. I need to pass some authentication parameters in the head section.
My code is as follows
def String WSDL_URL = 'http://ws.tradetracker.com/soap/affiliate?wsdl'
def http = new HTTPBuilder( WSDL_URL , ContentType.TEXT )
String soapEnvelope =
"""<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap-env:Header>
<authenticate>
<customerID>id</customerID>
<passphrase>pass</passphrase>
<demo>true</demo>
</authenticate>
</soap-env:Header>
<soap12:Body>
<getConversionTransactions xmlns="xmlns':'http://schemas.xmlsoap.org/wsdl">
<affiliateSiteID>id</affiliateSiteID>
</getConversionTransactions>
</soap12:Body>
</soap12:Envelope>"""
http.request( Method.POST, ContentType.TEXT ) {
body = soapEnvelope
response.success = { resp, xml ->
String xm = xml.readLines()
println "XML was ${xm}"
def territories = new XmlSlurper().parseText(
'<?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="urn:http://ws.webgains.com/aws.php" xmlns:enc="http://www.w3.org/2003/05/soap-encoding" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><env:Body xmlns:rpc="http://www.w3.org/2003/05/soap-rpc"><ns1:getFullUpdatedEarningsResponse env:encodingStyle="http://www.w3.org/2003/05/soap-encoding"><rpc:result>return</rpc:result><return enc:itemType="ns1:fullLinesArray" enc:arraySize="1" xsi:type="ns1:fullReportArray"><item xsi:type="ns1:fullLinesArray"><transactionID xsi:type="xsd:int">39367137</transactionID><affiliateID xsi:type="xsd:int">59987</affiliateID><campaignName xsi:type="xsd:string">www.tikcode.com</campaignName><campaignID xsi:type="xsd:int">136755</campaignID><date xsi:type="xsd:dateTime">2013-05-13T15:04:48</date><validationDate xsi:type="xsd:dateTime">2013-05-13T15:04:48</validationDate><delayedUntilDate xsi:type="xsd:string"></delayedUntilDate><programName xsi:type="xsd:string">Miniinthebox - US</programName><programID xsi:type="xsd:int">4611</programID><linkID xsi:type="xsd:string">95661</linkID><eventID xsi:type="xsd:int">7285</eventID><commission xsi:type="xsd:float">0.06</commission><saleValue xsi:type="xsd:float">0.8</saleValue><status xsi:type="xsd:string">confirmed</status><paymentStatus xsi:type="xsd:string">notcleared</paymentStatus><changeReason xsi:nil="true"/><clickRef xsi:nil="true"/><clickthroughTime xsi:type="xsd:dateTime">2013-05-13T14:58:33</clickthroughTime><landingPage xsi:type="xsd:string">http%3A%2F%2Fwww.lightinthebox.com%2Fes%2F%3Flitb_from%3Daffiliate_webgains</landingPage><country xsi:type="xsd:string">ES</country><referrer xsi:type="xsd:string">http%3A%2F%2Flocalhost%3A8080%2Fcom.publidirecta.widget%2Fpromocion%2FverPromocion%3Fpromocion%3D</referrer></item></return></ns1:getFullUpdatedEarningsResponse></env:Body></env:Envelope>').declareNamespace("ns1":"http://ws.webgains.com/aws.php")
println "aaaaaaaaaaaaaaaa"+ territories.Body.getFullUpdatedEarningsResponse.return.item.transactionID
}
response.failure = { resp, xml ->
println "pues peto, no se porque"+xml.readLines()
}
}
Im getting the following error and I dont have any clue wants wrong
<?xml version="1.0" encoding="UTF-8"?>, <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"><env:Body><env:Fault><env:Code><env:Value>env:Sender</env:Value></env:Code><env:Reason><env:Text>Body must be present in a SOAP envelope</env:Text></env:Reason></env:Fault></env:Body></env:Envelope>
Namespace for Envelope and its corresponding Header element is mismatching.
<soap12:Envelope> should have <soap12:Header> instead you have <soap-env:Header>. The payload becomes invalid in the header element so body becomes unreachable.
Like #dmahapatro said you have a problem in your XML. Anyway checking your code I've noted that you are using HTTPBuilder directly. Maybe you can try to use groovy-wslite (https://github.com/jwagenleitner/groovy-wslite) to make SOAP requests. It's very simple to call and process the response. There is a plugin for Grails, despite I'm not using the plugin, but the groovy-wslite directly.
BuildConfig.groovy
dependencies {
compile 'com.github.groovy-wslite:groovy-wslite:0.7.2'
runtime 'com.github.groovy-wslite:groovy-wslite:0.7.2'
}
In a Grails Service for instance:
def cnpj = "999999999906"
def clientSOAP = new SOAPClient('https://www.soawebservices.com.br/webservices/producao/cdc/cdc.asmx')
def response = clientSOAP.send (SOAPVersion.V1_2,
"""<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<PessoaJuridicaNFe xmlns="SOAWebServices">
<Credenciais>
<Email>xxxxx</Email>
<Senha>xxxxx</Senha>
</Credenciais>
<Documento>${cnpj}</Documento>
</PessoaJuridicaNFe>
</soap12:Body>
</soap12:Envelope>"""
)
//processing the response (very simple...)
Client client = new Client()
client.webServiceMsg = response.PessoaJuridicaNFeResponse.PessoaJuridicaNFeResult.Mensagem.text()
client.nome = response.PessoaJuridicaNFeResponse.PessoaJuridicaNFeResult.RazaoSocial.text()
//etc...

SOAPAction is empty

I have the same web application running on Mac and on Linux.
On Mac, I'm using Savon 0.7.6 and the web app is running perfectly ; the app initiates a SOAP Request as follows:
client = Savon::Client.new("http://pvwatts.nrel.gov/PVWATTS.asmx?WSDL")
req = prep_request(#locationId, #dc_rating, #tilt, #azimuth, #derate, #array_type, #cost)
response = client.get_pvwatts{|soap| soap.input = "GetPVWATTS"; soap.body = req }
rdata = response.to_hash
which results in the following request:
Retrieving WSDL from: http://pvwatts.nrel.gov/PVWATTS.asmx?WSDL
SOAP request: http://pvwatts.nrel.gov/PVWATTS.asmx
SOAPAction: http://pvwatts.nrel.gov/GetPVWATTS, Content-Type: text/xml;charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:wsdl="http://pvwatts.nrel.gov" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><wsdl:GetPVWATTS><wsdl:derate>0.8</wsdl:derate><wsdl:latitude>-99.0</wsdl:latitude><wsdl:pwrdgr>-0.005</wsdl:pwrdgr><wsdl:cost>0.1</wsdl:cost><wsdl:locationID>23234</wsdl:locationID><wsdl:inoct>45.0</wsdl:inoct><wsdl:mode>0</wsdl:mode><wsdl:key><key></wsdl:key><wsdl:azimuth>230</wsdl:azimuth><wsdl:tilt>20</wsdl:tilt><wsdl:DCrating>1</wsdl:DCrating><wsdl:longitude>0.0</wsdl:longitude></wsdl:GetPVWATTS></env:Body></env:Envelope>
Notice that SOAPAction field is populated
On Linux, I use savon version 1.2.0 with the following syntax:
client = Savon::Client.new do
wsdl.document = "http://pvwatts.nrel.gov/PVWATTS.asmx?WSDL"
end
req = prep_request(#locationId, #dc_rating, #tilt, #azimuth, #derate, #array_type, #cost)
response = client.request :wsdl, "GetPVWATTS" do
soap.body = req
end
rdata response.to_hash
which results in the following error:
SOAP request: http://pvwatts.nrel.gov/PVWATTS.asmx
Content-Length: 750, Content-Type: text/xml;charset=UTF-8, SOAPAction: ""
<?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:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="http://pvwatts.nrel.gov" xmlns:wsdl="http://pvwatts.nrel.gov"><env:Body><ins0:GetPVWATTS><wsdl:inoct>45.0</wsdl:inoct><wsdl:tilt>20</wsdl:tilt><wsdl:cost>0.1</wsdl:cost><wsdl:locationID>23234</wsdl:locationID><wsdl:mode>0</wsdl:mode><wsdl:DCrating>1</wsdl:DCrating><wsdl:key><key></wsdl:key><wsdl:pwrdgr>-0.005</wsdl:pwrdgr><wsdl:latitude>-99.0</wsdl:latitude><wsdl:azimuth>180</wsdl:azimuth><wsdl:longitude>0.0</wsdl:longitude><wsdl:derate>0.8</wsdl:derate></ins0:GetPVWATTS></env:Body></env:Envelope>
SOAP response (status 500):
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>Server did not recognize the value of HTTP Header SOAPAction: .</faultstring><detail /></soap:Fault></soap:Body></soap:Envelope>
Completed 500 Internal Server Error in 1065ms
Savon::SOAP::Fault ((soap:Client) Server did not recognize the value of HTTP Header SOAPAction: .):
Notice that SOAPAction field is NOT populated.
Anyone can tell me what's wrong here?
I figured out the solution ; my working code is the following:
response = client.request :wsdl, "get_pvwatts" do
soap.body = req
end
rdata = response.to_hash

Resources