Why Is "Wsdl" Namespace Interjected into Action Name When Using Savon for Ruby Soap Communication

Why is wsdl namespace interjected into action name when using savon for ruby soap communication?

Steve, you see that wsdl: in front of ProcessMessage tag? - I thought that was the only thing that was throwing me off but its not ( by the way it's hard set in soap.rb in Savon lib on line 160). That even if I don't spacify it in soap.namespaces - it's hard generated and attached in final xml. Which is not allowed by my service.

While the xml that is generated is a valid xml - it's not complete by the requirments of the service I'm trying to talk to. I.e.: in generated xml,

<?xml version="1.0" encoding="UTF-8"?>

tag is missing, also, I need PayloadManifest in the header,plus I need wsu:created and wsu:expires in my wsse: tag, but they are not implemented, etc., etc. a bunch of other little quirks that are too specific to my case. However soap has a private method = xml_body. Also soap lib in to_xml method is checking whether @xml_body was already set, before generating it's own xml. So I ended up slighly modifying behavior of soap. by making soap.xml_body = publicly accessable. So I was able to do:

response = client.process_message! do |soap| 
soap.action = "http://www.starstandards.org/webservices/2005/10/transport/operations/ProcessMessage"
soap.xml_body = "MY XML STRING GENERATED ELSEWHERE GOES HERE"
end

Which finally works!!!!

I'll suggest this to rubii - if this option becomes available that will solve a lot rare cases - where people can generate their custom xml and use the rest of savon lib.

consume soap service with ruby and savon

This is a problem with the way Savon handles Namespaces. See this answer Why is "wsdl" namespace interjected into action name when using savon for ruby soap communication?

You can resolve this by specifically calling soap.input and passing it an array, the first element is the method and the second is a hash containing the namespace(s)

require 'rubygems'
require 'savon'

client = Savon::Client.new "http://www.webservicex.net/stockquote.asmx?WSDL"
client.get_quote do |soap|
soap.input = [
"GetQuote",
{ "xmlns" => "http://www.webserviceX.NET/" }
]
soap.body = {:symbol => "AAPL"}
end

Talking with a SOAP service using Savon gem in Ruby

Thanks to Steve, I found "Why is “wsdl” namespace interjected into action name when using savon for ruby soap communication?" where Nick and Steve were talking about a similar problem.

Like Nick, my problem was in the way Savon is cooking up a SOAP envelope. As recommended by Nick, I ended up monkey patching a couple of methods in the Savon SOAP class. It's in lib/savon/soap.rb
and I'm good to go now.

I'm a novice when it comes to SOAP and it's my first time writing a SOAP client, but honestly it SUCKS! I still remember my first time writing a client for a REST service and gosh it was fun.

REST ROCKS, SOAP SUCKS. that's all!

SAVON setting envelope namespace in the envelope

What I have done in the past was the following (I always preferred to go without WSDL). Perhaps you can use it:

#!/usr/bin/env ruby

require 'savon'

additional_ns = {
'xmlns:api' => "http://api.notes.xyz.com/"
}

client = Savon.client(
:endpoint => "http://www.example.com/endpoint",
:namespace => "xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/",
:namespaces => additional_ns,
:log => true,
:log_level => :debug,
:pretty_print_xml => true,
:ssl_verify_mode => :none
)

client.call(....)

Remove namespace from Savon SOAP request

These changes solved my problem.

client.request(:web, "CreateMailer") do |soap|
soap.input = [
"CreateMailer", {
xmlns: "https://www.cfhdocmail.com/LiveAutoAPI/"
}
]
soap.element_form_default = :unqualified
soap.body = {
Username: "Username",
Password: "Password",
ProductType: "A4Letter",
IsMono: false,
IsDuplex: true,
DespatchASAP: false,
DespatchDate: Time.parse("2012-04-09"),
AddressNameFormat: "Full Name",
ReturnFormat: "JSON"
}
client.http.headers.delete("SOAPAction")
end

Thanks @sluukkonen for the help.

How to access wash out soap actions directly with passing action name in query string?

It is possible. Use send to call the action that you want. Note that this will only work if the other action explicitly calls render at the end of the action. Also, do not trust the :action_name param. Consider checking the :action_name against a whitelist of allowed actions before using it and raise an error if it's invalid.

class DummySoapController < ApplicationController
soap_service namespace: 'urn:WashOut'

def action
send(params[:action_name])
end

soap_action "convert_to_string", :args => :integer, :return => :string

def convert_to_string
render :soap => params[:value].to_s
end

soap_action "convert_to_integer", :args => :integer, :return => :float

def convert_to_float
render :soap => params[:value].to_f
end

end

For example, to get a string value you would use the URL

http://example.com/dummy_soap/action?action_name=convert_to_string&value=1

Or to get a float

http://example.com/dummy_soap/action?action_name=convert_to_float&value=1



Related Topics



Leave a reply



Submit