savon multiple namespace in body - ruby-on-rails

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.

Related

HTTParty POST call returning invalid JSON

I am looking to post to an API with my email address, but I cannot get a workable response. When I simply cURL the API in the terminal, the data is returned as expected.
#omnics2 = HTTParty.post('https://qo.api.liveramp.com/v1/idl_resolution',
:headers => {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'X-Api-Key' => 'my api key',
'Accept-Encoding' => 'gzip, deflate',
'Content-Length' => '59148'
},
:body => {'email' => 'me#email.com'}
)
The above returns this error
<HTTParty::Response:0x7ff5b0d49ab0 parsed_response="Invalid JSON in request: invalid character 'e' looking for beginning of value\n", #response=#<Net::HTTPBadRequest 400 Bad Request readbody=true>, #headers={"content-type"=>["text/plain; charset=utf-8"], "x-content-type-options"=>["nosniff"], "date"=>["Fri, 02 Aug 2019 21:41:58 GMT"], "content-length"=>["78"], "via"=>["1.1 google"], "alt-svc"=>["clear"], "connection"=>["close"]}>
I can wrap the entire call with a .to_json method, which allows for a succesful call, I just can't do anything with the response using the standard #omnics.body method. When I wrap everything in a .to_json method, this is the result I get:
=> "{\"content-type\":[\"text/plain; charset=utf-8\"],\"x-content-type-options\":[\"nosniff\"],\"date\":[\"Fri, 02 Aug 2019 21:45:32 GMT\"],\"content-length\":[\"78\"],\"via\":[\"1.1 google\"],\"alt-svc\":[\"clear\"],\"connection\":[\"close\"]}"
I've tried adding to_json methods to the header section and body sections, as recommended here like so:
:body => {'email' => 'me#email.com'}.to_json instead of wrapping the entire function, but that also errors out.
Would love any thoughts here as I am merely a hobbiest developer and am probably overlooking something obvious.
Finally got this to work. I had to make the body values enclosed within an array. Here's the syntax:
#omnics3 = HTTParty.post("https://qo.api.liveramp.com/v1/idl_resolution", options)
options = {
headers: {
"Content-Type": "application/json",
"X-Api-Key" => "my api key"
},
:debug_output => STDOUT,
query: { data: true },
body: [
{ email: ["anemail#address.com"] },
{ email: ["joe#gmail.com"] },
].to_json
}

Why request sending error Savon::SOAPFault: (ns1:SecurityError)

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" })

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"

Resources