Why request sending error Savon::SOAPFault: (ns1:SecurityError) - ruby-on-rails

I am getting this error from the SOAP actions integration.
Savon::SOAPFault: (ns1:SecurityError) A security error was encountered when verifying the message
my Savon client look like this:
client = Savon.client(wsdl: "https://212.154.167.194:9443/esf-web/ws/api1/SessionService?wsdl",
ssl_verify_mode: :none,
env_namespace: :soapenv,
pretty_print_xml: true,
namespace_identifier: :nam,
env_namespace: :soapenv,
namespaces: { "xmlns:nam" => "namespace.esf" },
:raise_errors => true,
log: true,
#loglevel: :debug,
pretty_print_xml: true)
message = {
"createSessionRequest" =>
{
"tin" => "placeholder",
"x509Certificate" => "placeholder"
}
}
and generated responce
response = client.call(:create_session, message: {:tin => 'XXXX', :x509Certificate => 'xxxxxx'})
The XML code should be here:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:esf="esf">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-664678CEF9FFC67AD214168421472821">
<wsse:Username>123456789011</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security></soapenv:Header>
<soapenv:Body>
<esf:createSessionRequest>
<tin>?</tin>
<!--Optional:-->
<projectCode>?</projectCode>
<x509Certificate>?</x509Certificate>
</esf:createSessionRequest>
</soapenv:Body>
</soapenv:Envelope>
Please help

In the xml you have the following username and password
<wsse:Username>123456789011</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
Where do you set those username and password?
Read the guide so that you can follow their steps to configure Savon:
response = client.call(:authenticate, message: { username: "luke", password: "secret" })

Related

savon multiple namespace in body

I am new to Savon2
and passing wsdl url to the Savon.Client, and getting proper response in header, but I am not getting how to pass multiple namespace to the body:
Savon.client(wsdl: 'https://someUrl.com/abcd?wsdl', ssl_verify_mode: :none, pretty_print_xml: true, log: true, env_namespace: :soapenv, namespace_identifier: nil) do
wsse_auth("api_demo_account", "somePassword", :digest)
end
client.call(:operation_name, message: {
"api01Req" => [{"shipCode" => 'ABC', "shipAmount" => 1123,
"countryCode" => "USA"}
]},
'attributes' => { "xmlns" => "http://someUrl.com" })
and it is generating code for body like this:
<soapenv:Body>
<operationName xmlns="http://someUrl.com">
<xmlns:api01Req>
<shipCode>ABC</shipCode>
<shipAmount>1123</shipAmount>
<countryCode>USA</countryCode>
</xmlns:api01Req>
</operationName>
</soapenv:Body>
But I need a request like this:
<soapenv:Body>
<operationName xmlns="http://someUrl.com">
<api01Req>
<ns1:shipCode xmlns:ns1="http://someOtherUrl.com">ABC
</ns1:shipCode>
<ns2:shipAmount xmlns:ns2="http://someOtherUrl.com">1123
</ns2:shipAmount>
<ns3:countryCode xmlns:ns3="http://someOtherUrl.com">USA
</ns3:countryCode>
</api01Req>
</getTotalPostage>
</soapenv:Body>
like here it is generating ns1, ns2, ns3, etc along with xmlns:ns1, xmlns:ns2, etc.. different URL's, how should I modify the code to get like above request.

Can't specify header in SOAP call using Savon

When calling to an API for retrieving labels for post parcels I get frustrated with how hard it is to set up a SOAP call with ruby.
I know that the following works from a sandbox environment:
this is the SHOULD BE call
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode</Action>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>devc_!R4xc8p9</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">098fd559930983af31ef6630a0bb0c1974156561</wsse:Password>
</wsse:UsernameToken>
</Security>
</s:Header>
<s:Body>
<GenerateBarcode xmlns:d6p1="http://postnl.nl/cif/domain/BarcodeWebService/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://postnl.nl/cif/services/BarcodeWebService/">
<d6p1:Message>
<d6p1:MessageID>5</d6p1:MessageID>
<d6p1:MessageTimeStamp>28-06-2017 14:15:41</d6p1:MessageTimeStamp>
</d6p1:Message>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode>
</GenerateBarcode>
</s:Body>
</s:Envelope>
EDIT
As sugested I used build_request to inspect how my request looks. It actually looks like this:
<?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="http://tempuri.org/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
<Username>devc_!R4xc8p9</Username
<Password>098fd559930983af31ef6630a0bb0c1974156561</Password>
</env:Header>
<env:Body><wsdl:GenerateBarcode><CustomerCode>DEVC</CustomerCode>
<CustomerNumber>11223344</CustomerNumber>
<Type>3S</Type>
<Range>DEVC</Range>
<Serie>1000000-2000000</Serie>
</wsdl:GenerateBarcode>
</env:Body>
</env:Envelope>
Comparing that with the xml above, it becomes clear that stuff is off. How to handle nesting?
This is when I build it myself like:
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
message customer_code: 'DEVC',
customer_number: 11223344,
type: '3S',
range: 'DEVC',
serie: '1000000-2000000'
end
I know my connection works, but also get back:
{:fault=>{:faultcode=>"s:CIF Framework Message Interceptor",
:faultstring=>"Check CIFException in the detail section", :detail=>
{:cif_exception=>{:errors=>{:exception_data=>{:description=>nil,
:error_msg=>"Username/password is not specified.",
:error_number=>"3"}},
:#xmlns=>"http://postnl.nl/cif/services/common/",
:"#xmlns:i"=>"http://www.w3.org/2001/XMLSchema-instance"}}}}
So already in my header stuff goes wrong. Username/password is not specified. I've tried several combinations and I don't get why.
Update
#client = Savon.client(
:env_namespace => :s,
# :namespace_identifier => :none, # :none doesn't work... gets interpreted literary. Out-commeting gives wsdl:GenerateBarcode
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:endpoint => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/BarcodeWebService.svc',
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl')
soap_header = {
"Security" => {
"UsernameToken" => {
"Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
}
}
message = {
"d6p1:Customer" => {
"d6p1:CustomerCode" => 'DEVC',
"d6p1:CustomerNumber" => 11223344
},
"d6p1:Barcode" => {
"d6p1:Type" => '3S',
"d6p1:Range" => 'DEVC',
"d6p1:Serie" => '1000000-2000000'
}
}
#request = #client.build_request(:generate_barcode) do
soap_header soap_header
message message
end
#response = #client.call(:generate_barcode) do
soap_header soap_header
message message
Which builds the following request:
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://tempuri.org/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Security>
<UsernameToken>
<Username>devc_!R4xc8p9</Username
<Password>098fd559930983af31ef6630a0bb0c1974156561</Password>
</UsernameToken>
</Security>
</s:Header>
<s:Body>
<wsdl:GenerateBarcode>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode></s:GenerateBarcode>
</s:Body>
For as of yet, I get errors adding the wsse: namespace straight in the soap_header hash.
EDIT 2
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="http://tempuri.org/"
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode
</Action>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken>
<Username>devc_!R4xc8p9</Username>
<Password>xxxxxxxx</Password>
</UsernameToken>
</Security>
</s:Header>
<s:Body>
<wsdl:GenerateBarcode>
<d6p1:Customer>
<d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
<d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
</d6p1:Customer>
<d6p1:Barcode>
<d6p1:Type>3S</d6p1:Type>
<d6p1:Range>DEVC</d6p1:Range>
<d6p1:Serie>1000000-2000000</d6p1:Serie>
</d6p1:Barcode>
</wsdl:GenerateBarcode>
</s:Body>
</s:Envelope>
Comparing this to my should be call it seems that my <s:envelope ...> tag has too much information.
I'll make a follow up question of this probably.
EDIT 3
I restarted at Complex SOAP call in Ruby on Rails using Savon gets weird around the envelope and main operation
The Message hash, should be nested in the same way as the call expects it something like
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Security" => {
"UsernameToken" => {
"Username" => 'devc_!R4xc8p9',
"Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
}
message "GenerateBarcode" => {
"Message" => {
"MessageID" => 5, #might be different
"MessageTime" => Time.now, #might be different depending on use case
},
"Customer" => {
"CustomerCode" => 'DEVC',
"CustomerNumber" => 11223344
},
"Barcode" => {
"Type" => '3S',
"Range" => 'DEVC',
"Serie" => '1000000-2000000'
}
}
end
EDIT
Referencing this page it looks like you can add the action tag and elements like this
'Action' => "http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode",
:attributes! => {
"s:mustUnderstand" => "1",
"xmlns" => "http://schemas.microsoft.com/ws/2005/05/addressing/none"
}
Referencing this page it looks like you can set the namespaces directly "wsse:UsernameToken" instead of "UsernameToken"
which should result in the following
#client = Savon.client(
:convert_request_keys_to => :camelcase,
:raise_errors => false,
:pretty_print_xml => true,
:wsdl => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
:headers => {
'Username' => 'devc_!R4xc8p9',
'Password' => '098fd559930983af31ef6630a0bb0c1974156561'
})
#response = #client.call(:generate_barcode) do
soap_header "Security" => {
"wsse:UsernameToken" => {
"wsse:Username" => 'devc_!R4xc8p9',
"wsse:Password" => '098fd559930983af31ef6630a0bb0c1974156561'
}
"Action" => "http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode",
:attributes! => {
"s:mustUnderstand" => "1",
"xmlns" => "http://schemas.microsoft.com/ws/2005/05/addressing/none"
}
}
message "GenerateBarcode" => {
"Message" => {
"MessageID" => 5, #might be different
"MessageTime" => Time.now, #might be different depending on use case
},
"Customer" => {
"CustomerCode" => 'DEVC',
"CustomerNumber" => 11223344
},
"Barcode" => {
"Type" => '3S',
"Range" => 'DEVC',
"Serie" => '1000000-2000000'
}
}
end

Savon SOAP Request not working

I'm using Savon gem in my Rails app and I need to submit my form fields to Equifax.
Here's the Equifax XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v3="http://eid.equifax.com/soap/schema/canada/v3">
<soapenv:Header/>
<soapenv:Body>
<v3:InitialRequest>
<v3:Identity>
<v3:Name>
<v3:FirstName>Michael</v3:FirstName>
<v3:LastName>Smith</v3:LastName>
</v3:Name>
<!--1 to 3 repetitions:-->
<v3:Address timeAtAddress="72" addressType="current">
<v3:HybridAddress>
<!--1 to 6 repetitions:-->
<v3:AddressLine>1028 Summerville</v3:AddressLine>
<v3:City>Vancouver</v3:City>
<v3:Province>BC</v3:Province>
<v3:PostalCode>V7B0A8</v3:PostalCode>
</v3:HybridAddress>
</v3:Address>
<!--Optional:-->
<v3:DateOfBirth>
<v3:Day>26</v3:Day>
<v3:Month>08</v3:Month>
<v3:Year>1984</v3:Year>
</v3:DateOfBirth>
<v3:PhoneNumber phoneType="current">
<v3:PhoneNumber>6045556666</v3:PhoneNumber>
</v3:PhoneNumber>
</v3:Identity>
<v3:ProcessingOptions>
<v3:Language>English</v3:Language>
</v3:ProcessingOptions>
</v3:InitialRequest>
</soapenv:Body>
</soapenv:Envelope>
This is my Ruby code making the SOAP Request.
<%= client.call(:start_transaction, message: { "v3:InitialRequest" => { "v3:Identity" => { "v3:Name" => { "v3:FirstName" => "michael", "v3:LastName" => "Smith"}, "v3:Address" => {"v3:AddressLine" => "233 Cambie St", "v3:City" => "Vancouve", "v3:Province" => "BC", "v3:PostalCode" => "V6B0E8"}, "v3:DateOfBirth" => {"v3:Day" => "26", "v3:Month" => "08", "v3:Year" => "1984"}, "v3:PhoneNumber" => {"v3:PhoneNumber" => "6048885555"}}}, attributes: { "v3:Address" => { "timeAtAddress" => "72", "addressType" => "current"}}) %>
The error message that is returned: (soap:Client) Error reading XMLStreamReader.
Can someone point me in the right direction?
Please try the below way by sending one string of that xml
xml_str = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v3="http://eid.equifax.com/soap/schema/canada/v3"><soapenv:Header/><soapenv:Body><v3:InitialRequest><v3:Identity><v3:Name><v3:FirstName>Michael</v3:FirstName><v3:LastName>Smith</v3:LastName></v3:Name><!--1 to 3 repetitions:--><v3:Address timeAtAddress="72" addressType="current"><v3:HybridAddress><v3:AddressLine>1028 Summerville</v3:AddressLine><v3:City>Vancouver</v3:City><v3:Province>BC</v3:Province><v3:PostalCode>V7B0A8</v3:PostalCode></v3:HybridAddress></v3:Address><v3:DateOfBirth><v3:Day>26</v3:Day><v3:Month>08</v3:Month><v3:Year>1984</v3:Year></v3:DateOfBirth><v3:PhoneNumber phoneType="current"><v3:PhoneNumber>6045556666</v3:PhoneNumber></v3:PhoneNumber></v3:Identity><v3:ProcessingOptions><v3:Language>English</v3:Language></v3:ProcessingOptions></v3:InitialRequest></soapenv:Body></soapenv:Envelope>'
client.call(:start_transaction, xml: xml_str)
Remember you can use here document to made the xml string but the string should not consis "\n

how to pass Security header in savon 2.7 with Rails 4

my require header is
<SOAP-ENV:Header xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Security SOAP-ENV:mustUnderstand="1">
<wsse:UsernameToken>
<wsse:Username>123</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">1234</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
this is my message :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:dictionary:com.test.webservices">
<soapenv:Body>
<urn:getPIN/>
</soapenv:Body>
</soapenv:Envelope>
my code
soap_header = {
"wsse:Security" => {
"#soapenv:mustUnderstand" => 1,
"wsse:UsernameToken" =>{
"Username" => "123",
"Password" => "1234",
"digest" => false
}
}
}
client = Savon.client(wsdl: #wsdl, log: true,:ssl_verify_mode => :none,:soap_header=> soap_header)
response = client.call :getPIN, xml: #message
how to pass header in Savon 2.7 we not able to access services please help us.
Try this please (found on Savon 2 documentation):
Savon.client(wsse_auth: ["123", "1234"])
The soap endpoint I was contacting was very picky and I had this same problem. (wsse_auth did not work)
I solved this by modifying your answer slightly.
soap_header = {
"wsse:Security" => {
"#soapenv:mustUnderstand" => 1,
"#xmlns:soap" => "http://schemas.xmlsoap.org/wsdl/soap/",
"#xmlns:wsse" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
"wsse:UsernameToken" =>{
"wsse:Username" => "123",
"wsse:Password" => "12345",
}
}
}
The problem was the missing soapenv:mustUnderstand="1"

Converting raw XML query to Savon 2 Format

I'm forced to enter the world of soap and having a bit of an issue, using Savon.
The wsdl is: http://evernet.nwmls.com/evernetqueryservice/evernetquery.asmx?wsdl
And if I use the test form for this data provider, I'm able to receive data without error using the following format:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<EverNetQuerySpecification xmlns="urn:www.nwmls.com/Schemas/General/EverNetQueryXML.xsd">
<Message>
<Head>
<UserId>my_username_here</UserId>
<Password>my_password_here</Password>
<SchemaName>StandardXML1_2</SchemaName>
</Head>
<Body>
<Query>
<MLS>nwmls</MLS>
<PropertyType>RESI</PropertyType>
<BeginDate>2014-04-20T00:25:00</BeginDate>
<EndDate>2014-04-22T00:25:00</EndDate>
</Query>
<Filter />
</Body>
What I'm trying to do with Savon 2.2 to replicate this in my rails app is:
client = Savon.client(:wsdl => "http://evernet.nwmls.com/evernetqueryservice/evernetquery.asmx?wsdl")
response = client.call(:retrieve_listing_data) do |locals|
locals.message "Query" => {"Head" => {"UserId" => "my_username_here", "Password" => "my_password_here", "SchemaName" => "StandardXML1_2"}, "Body" => {"MLS" => "nwmls", "PropertyType" => "RESI", "BeginDate" => "2014-04-17T00:25:00", "EndDate" => "2014-04-22T00:25:00"}}
end
But I'm getting an error saying:
Value cannot be null. Parameter name: s
I'm a little bit lost in anything soap, but especially lost here because it seems that I'm including everything in my Savon syntax but must be missing something...
Edit: here's the full xml response with debugging on:
D, [2014-04-22T16:55:52.806716 #77213] DEBUG -- : HTTPI GET request to evernet.nwmls.com (net_http)
I, [2014-04-22T16:55:54.340990 #77213] INFO -- : SOAP request: http://evernet.nwmls.com/evernetqueryservice/evernetquery.asmx
I, [2014-04-22T16:55:54.341077 #77213] INFO -- : SOAPAction: "http://www.nwmls.com/EverNetServices/RetrieveListingData", Content-Type: text/xml;charset=UTF-8, Content-Length: 682
D, [2014-04-22T16:55:54.341120 #77213] DEBUG -- : <?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:tns="http://www.nwmls.com/EverNetServices" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><tns:RetrieveListingData><tns:Query><tns:Head><tns:Head>hoverboard</tns:Head><tns:Password>cP6cHias</tns:Password><tns:SchemaName>StandardXML1_2</tns:SchemaName></tns:Head><tns:Body><tns:MLS>nwmls</tns:MLS><tns:PropertyType>RESI</tns:PropertyType><tns:BeginDate>2014-04-17T00:25:00</tns:BeginDate><tns:EndDate>2014-04-22T00:25:00</tns:EndDate></tns:Body></tns:Query></tns:RetrieveListingData></env:Body></env:Envelope>
D, [2014-04-22T16:55:54.341255 #77213] DEBUG -- : HTTPI POST request to evernet.nwmls.com (net_http)
I, [2014-04-22T16:55:54.678125 #77213] INFO -- : SOAP response (status 200)
D, [2014-04-22T16:55:54.678292 #77213] DEBUG -- : <?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><RetrieveListingDataResponse xmlns="http://www.nwmls.com/EverNetServices"><RetrieveListingDataResult><Listings>
<ResponseMessages>
<Message>Value cannot be null.
Parameter name: s</Message>
</ResponseMessages>
</Listings></RetrieveListingDataResult></RetrieveListingDataResponse></soap:Body></soap:Envelope>
=> #<Savon::Response:0x007f844230e4e0 #http=#<HTTPI::Response:0x007f844230fc00 #code=200, #headers={"cache-control"=>"private, max-age=0", "content-type"=>"text/xml; charset=utf-8", "server"=>"Microsoft-IIS/7.5", "x-aspnet-version"=>"4.0.30319", "x-powered-by"=>"ASP.NET", "date"=>"Tue, 22 Apr 2014 23:55:54 GMT", "content-length"=>"574"}, #raw_body="<?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><RetrieveListingDataResponse xmlns=\"http://www.nwmls.com/EverNetServices\"><RetrieveListingDataResult><Listings>\r\n <ResponseMessages>\r\n <Message>Value cannot be null.\r\nParameter name: s</Message>\r\n </ResponseMessages>\r\n</Listings></RetrieveListingDataResult></RetrieveListingDataResponse></soap:Body></soap:Envelope>", #body="<?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><RetrieveListingDataResponse xmlns=\"http://www.nwmls.com/EverNetServices\"><RetrieveListingDataResult><Listings>\r\n <ResponseMessages>\r\n <Message>Value cannot be null.\r\nParameter name: s</Message>\r\n </ResponseMessages>\r\n</Listings></RetrieveListingDataResult></RetrieveListingDataResponse></soap:Body></soap:Envelope>">, #globals=#<Savon::GlobalOptions:0x007f8447489a40 #option_type=:global, #options={:encoding=>"UTF-8", :soap_version=>1, :namespaces=>{}, :logger=>#<Logger:0x007f84474899c8 #progname=nil, #level=0, #default_formatter=#<Logger::Formatter:0x007f84474899a0 #datetime_format=nil>, #formatter=nil, #logdev=#<Logger::LogDevice:0x007f8447489950 #shift_size=nil, #shift_age=nil, #filename=nil, #dev=#<IO:<STDOUT>>, #mutex=#<Logger::LogDevice::LogDeviceMutex:0x007f8447489928 #mon_owner=nil, #mon_count=0, #mon_mutex=#<Mutex:0x007f84474898d8>>>>, :log=>true, :filters=>[], :pretty_print_xml=>false, :raise_errors=>true, :strip_namespaces=>true, :convert_response_tags_to=>#<Proc:0x007f8447489860#/Users/seth/.rvm/gems/ruby-2.0.0-p195/gems/savon-2.4.0/lib/savon/options.rb:56 (lambda)>, :multipart=>false, :wsdl=>"http://evernet.nwmls.com/evernetqueryservice/evernetquery.asmx?wsdl"}>, #locals=#<Savon::LocalOptions:0x007f84443732a8 #option_type=:local, #options={:advanced_typecasting=>true, :response_parser=>:nokogiri, :multipart=>false, :message=>{"Query"=>{"Head"=>{"Head"=>"my_username", "Password"=>"my_password", "SchemaName"=>"StandardXML1_2"}, "Body"=>{"MLS"=>"nwmls", "PropertyType"=>"RESI", "BeginDate"=>"2014-04-17T00:25:00", "EndDate"=>"2014-04-22T00:25:00"}}}}>>
I recently dealt with this same problem. NWMLS uses a special root key called v_strXmlQuery that includes a nested XML string. This works just fine for me:
[1] pry(main)> require 'savon'
=> true
[2] pry(main)> client = Savon.client(
[2] pry(main)* wsdl: "http://evernet.nwmls.com/evernetqueryservice/evernetquery.asmx?wsdl",
[2] pry(main)* convert_request_keys_to: :none); # this is important
=> #<Savon::Client:0x007fbf5a324288
...
[4] pry(main)> username = 'myusername'
[5] pry(main)> password = 'mypassword'
[7] pry(main)> message = {v_strXmlQuery:"<?xml version=\"1.0\" encoding=\"UTF-8\"?><EverNetQuerySpecification xmlns=\"urn:www.nwmls.com/Schemas/General/EverNetQueryXML.xsd\"><Message><Head><UserId>#{username}</UserId><Password>#{password}</Password><SchemaName>#{schema_name}</SchemaName></Head><Body><Query><MLS>NWMLS</MLS><PropertyType>RESI</PropertyType><Status>A</Status><County>King</County><City>Seattle</City><BeginDate>2005-08-27T16:14:09</BeginDate><EndDate>2015-08-28T09:14:09</EndDate></Query><Filter></Filter></Body></Message></EverNetQuerySpecification>"}y><BeginDate>2005-08-27T16:14:09</BeginDate><EndDate>2015-08-28T09:14:09</EndDate></Query><Filter></Filter></Body></Message></EverNetQuerySpecification>"}
=> {:v_strXmlQuery=>
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><EverNetQuerySpecification xmlns=\"urn:www.nwmls.com/Schemas/General/EverNetQueryXML.xsd\"><Message><Head><UserId>myusername</UserId><Password>mypassword</Password><SchemaName>StandardXML1_3</SchemaName></Head><Body><Query><MLS>NWMLS</MLS><PropertyType>RESI</PropertyType><Status>A</Status><County>King</County><City>Seattle</City><BeginDate>2005-08-27T16:14:09</BeginDate><EndDate>2015-08-28T09:14:09</EndDate></Query><Filter></Filter></Body></Message></EverNetQuerySpecification>"}
[8] pry(main)> client.call(:retrieve_listing_data, message: message).body
...
=> {:retrieve_listing_data_response=>
{:retrieve_listing_data_result=>
"<Listings xmlns=\"http://www.nwmls.com/Schemas/Standard/StandardXML1_3.xsd\"><Residential>...<MR>Timeless, top of the line finish work in this studs-out craftsman remodel. This remodel has everything desired in a home: open floor plan, rich hardwood flooring,...
I'd suggest using an XML builder like Savon's Gyoku gem to construct the sub hash and attach the xml header/footer, then inject it into the parent document query:
# takes a query hash and generates correctly-formatted SOAP-friendly XML
class QueryGenerator
def self.call(hash)
new.call(hash)
end
def call(hash)
_xml = Gyoku.xml(hash, key_converter: :camelcase)
repaired_xml = fix_weird_keys(_xml)
wrapped_xml = xml_header + repaired_xml + xml_footer
{ v_strXmlQuery: wrapped_xml }
end
def xml_header
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><EverNetQuerySpecification xmlns=\"urn:www.nwmls.com/Schemas/General/EverNetQueryXML.xsd\"><Message>"
end
def xml_footer
"</Message></EverNetQuerySpecification>"
end
# because its all Camelcase, except for that one that aint
def fix_weird_keys(xml_str)
xml_str.gsub('<Mls>','<MLS>').
gsub('</Mls>','</MLS>')
end
end
query_hash = {
head: {
user_id: 'myusername',
password: 'mypassword',
schema_name: 'StandardXML1_3'
},
body: {
query: {
mls: 'NWMLS',
property_type: 'RESI',
status: 'A',
city: 'Seattle',
begin_date: '2014-04-17T00:25:00',
end_date: '2014-04-22T00:25:00'
},
filter: {}
}
}
listing_data_query = QueryGenerator.call(query_hash)
client.call(:retrieve_listing_data, message: listing_data_query )
have you looked into the resulting XML message?
you should set the parameters
log => true,
log_level => :debug,
pretty_print_xml => true
and have a look.

Resources