how to specify namespace in SOAP request with 'savon' gem? - ruby

I am using recent version of savon gem and trying to send a SOAP request i am getting this error about invalid url:
Invalid URL: %7Bendpoint%20address%7D (ArgumentError)
from /home/vagrant/.rvm/gems/ruby-2.1.0/gems/httpi-2.3.0/lib/httpi/request.rb:27:in `url='
from /home/vagrant/.rvm/gems/ruby-2.1.0/gems/savon-2.8.0/lib/savon/operation.rb:103:in `build_request'
from /home/vagrant/.rvm/gems/ruby-2.1.0/gems/savon-2.8.0/lib/savon/operation.rb:51:in `call'
from /home/vagrant/.rvm/gems/ruby-2.1.0/gems/savon-2.8.0/lib/savon/client.rb:36:in `call'
My code is:
require "savon"
require "excon"
Excon.defaults[:ssl_verify_peer] = false
class Payback
attr_reader :connection, :client, :operation, :message
SOAP_URL = "https://partnertest.payback.in/PBExternalServices/v1/soap?wsdl"
def initialize operation, message
#client = Savon.client(wsdl: "https://partnertest.payback.in/PBExternalServices/v1/soap?wsdl", ssl_verify_mode: :none)
#operation = operation
#message = message
end
def response
#response ||= client.call(operation, message: message)
end
end
this is how i am using it.(I know something is wrong with namespaces)
payback = Payback.new :get_account_balance,
{"typ:Authentication" => { "typ1:Principal" => { "typ1:PrincipalValue" => 9899012182,
"typ1:PrincipalClassifier" => 3 }}}
payback.response
I need to construct this XML with savon
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://www.payback.net/lmsglobal/ws/v1/extint/types" xmlns:typ1="http://www.payback.net/lmsglobal/xsd/v1/types">
<soapenv:Header/>
<soapenv:Body>
<typ:GetAccountBalanceRequest>
<typ:Authentication>
<typ1:Principal>
<typ1:PrincipalValue>9899012182</typ1:PrincipalValue>
<typ1:PrincipalClassifier>3</typ1:PrincipalClassifier>
</typ1:Principal>
</typ:Authentication>
</typ:GetAccountBalanceRequest>
</soapenv:Body>
</soapenv:Envelope>
i don't know what i am doing wrong here, please help.

I noticed that on line 5820 of the WSDL file the location looks like this:
<soap:address location="{endpoint address}"/>
Could it be the problem?
Edited 1.
Open up in your browser: https://partnertest.payback.in/PBExternalServices/v1/soap?wsdl
Search for {endpoint address} string on the page.
I'm far from understand this particular WSDL document, but I wonder if there must be something else in place of {endpoint address}, like a real URI. E.g. could it be the WSDL document that has the problem?
Edited 2
Tried to remove the typ and typ1 which were not recognized by the service. Ended up with a working code that returns a valid response:
puts Savon.client(
wsdl: 'https://partnertest.payback.in/PBExternalServices/v1/soap?wsdl',
endpoint: 'https://partnertest.payback.in/PBExternalServices/v1/soap',
ssl_verify_mode: :none
).call(
:get_account_balance,
:message => {
'Authentication' => {
'Principal' => {
'PrincipalValue' => 9899012182,
'PrincipalClassifier' => 3
}
}
}
)

Related

Obtaining a render Argument Error: What is the correct syntax or usage?

I am new to Ruby, Sinatra and Pusher so this is a basic question. I am attempting to authenticate a Pusher Client (using iOS demo code https://github.com/lukeredpath/libPusher). The server code below fails with error when the iOS client attempts to join a presence channel:
ArgumentError - wrong number of arguments (1 for 2):
/Users/waveocean/.rvm/gems/ruby-1.9.3-p327/gems/sinatra-1.3.3/lib/sinatra/base.rb:665:in `render'
web.rb:13:in `auth'
web.rb:26:in `block in <main>'
/Users/waveocean/.rvm/gems/ruby-1.9.3-p327/gems/sinatra-1.3.3/lib/sinatra/base.rb:1265:in `call'
... snipped for brevity ...
Here is the code:
require 'sinatra'
require 'pusher'
require 'thin'
Thin::HTTP_STATUS_CODES[403] = "FORBIDDEN"
Pusher.app_id = 'MY-APP-ID'
Pusher.key = 'MY-KEY'
Pusher.secret = 'MY-SECRET'
def auth
response = Pusher[params[:channel_name]].authenticate(params[:socket_id], {:user_id => 101})
render :json => response
end
use Rack::Auth::Basic, "Protected Area" do |username, password|
username == 'foo' && password == 'bar'
end
post '/presence/auth' do
if params[:channel_name] == 'presence-demo'
auth
else
# render :text => "Forbidden", :status => '403'
response.status = 403
end
end
Can someone provide a suggestion or correct usage of render?
Here's is what I discovered. render is associated with Rails, and not strictly Ruby. To respond to the Sinatra route, use the following in the auth method:
def auth
response = Pusher[params[:channel_name]].authenticate(params[:socket_id], {:user_id => 101})
[200, {"Content-Type" => "application/json"}, response.to_json]
end
As it turns out, the Pusher iOS project demo provides a Scripts/auth_server.rb file with the required implementation. It is documented with the installation instructions here: https://github.com/lukeredpath/libPusher/wiki/Adding-libPusher-to-your-project .

soap4r SOAP::FaultError

I am new to soap and I am having the problems with it already! I am using soap4r gem.
gem 'soap4r', :git => 'git://github.com/felipec/soap4r.git'
require 'soap/wsdlDriver'
require 'soap/rpc/driver'
require 'soap/mapping/mapping.rb'
And I initialize the rpc driver as follows:
def initialize
#username = "username"
#password = "password"
endpoint = "https://someurl.php"
namespace = "abc:somenamespace"
#driver = SOAP::RPC::Driver.new(endpoint, namespace)
end
When I visit the endpoint from the browser I am getting this error:
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode>
<faultactor xsi:type="xsd:string"/>
<faultstring xsi:type="xsd:string">Operation '' is not defined in the WSDL for this service
</faultstring>
<detail xsi:type="xsd:string"/>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Also, when I do this from irb:
client = SOAP::WSDLDriverFactory.new("endpoint?wsdl").create_rpc_driver
I am getting this error:
RuntimeError: part: return cannot be resolved
from /home/sadiksha/.rvm/rubies/ruby-1.8.7-p358/lib/ruby/1.8/wsdl/soap/methodDefCreator.rb:144:in `rpcdefinedtype'
from /home/sadiksha/.rvm/rubies/ruby-1.8.7-p358/lib/ruby/1.8/wsdl/soap/methodDefCreator.rb:56:in `collect_rpcparameter'
.
.
.
But when I do this:
client = SOAP::WSDLDriverFactory.new(endpoint).createDriver
and list methods by
client.methods(false)
and I have one method getName. When I try to access that method by client.getName({:username => "username", :password => "password") it gives me error saying
SOAP::FaultError: Username doesn't exist
from
I am sorry for making it too long! I have been searching about it for a long time now. But was not able to find the specific answer. I hope someone will have answer to my question. I am thinking that it might be some authentication error.
Using the following can help you trouble shoot whats going on. It will dump the generated and received XML to console.
myWebServiceInstance.wiredump_dev = STDERR

Parse WSDL file with SOAP4R

Is there any example of WSDL Parser using SOAP4R? I'm trying to list all operations of WSDL file but I can't figure it out :( Can you post me some tutorial?
Thx
Maybe that isn't answer you want, but I recommend you switch to Savon. For example, your task looks like this snippet (this example taken from github's savon page):
require "savon"
# create a client for your SOAP service
client = Savon::Client.new("http://service.example.com?wsdl")
client.wsdl.soap_actions
# => [:create_user, :get_user, :get_all_users]
# execute a SOAP request to call the "getUser" action
response = client.request(:get_user) do
soap.body = { :id => 1 }
end
response.body
# => { :get_user_response => { :first_name => "The", :last_name => "Hoff" } }

Savon Ruby Soap Client - can't create a soap document correctly

I admit I'm new to both SOAP and Savon, but I got it working with another service, but this one is stumping me.
The WSDL is here:
http://stg-wholesale.carsdirect.com/ws/services/Ping?WSDL
The Document when done should look like this:
<?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>
<dealerPing xmlns="http://wholesale.carsdirect.com">
<request>
<partner>
<pricePlan>integer</pricePlan>
<id>integer</id>
</partner>
<vehicle>
<year>integer</year>
<make>string</make>
<model>string</model>
<trim>string</trim>
</vehicle>
<zipcode>integer</zipcode>
</request>
</dealerPing>
</soap:Body>
</soap:Envelope>
If anyone can get close to generating a document like this or give me some pointers I would greatly appreciate it.
I tried doing something like :
client = Savon::Client.new{|wsdl| wsdl.document = #cp.wsdl}
#response = client.dealer_ping do |soap|
...
end
But, I got this error : undefined method `dealer_ping' for #
I'm pretty much stuck at this point. My knowledge of both parts of this equation is lacking.
Thanks.
I don't have access to the service, so I can't try if it works ... but this should probably work:
client = Savon::Client.new do
wsdl.endpoint = "http://stg-wholesale.carsdirect.com/ws/services/Ping"
wsdl.namespace = "http://wholesale.carsdirect.com"
end
client.request(:dealer_ping) do
soap.body = {
:request => {
:partner => {
:price_plan => 123,
:id => 1222
},
:vehicle => {
:year => 2010,
:make => "Aston Martin",
:model => "DBS",
:trim => ""
},
:zipcode => 90245
}
}
end

Case problem in SOAP message tag names using savon

I'm using Ruby 1.9.2 with savon 0.9.2 on Windows 7 Professional 64 bit.
I need to call a web SOAP service that requires a security token that I get from a second web SOAP service. The code I use is as follows:
require 'savon'
client = Savon::Client.new "http://some.url?wsdl"
client.wsdl.soap_actions
start_session_response = client.request :start_session do
soap.input = ["StartSession", {:xmlns => "http://some.schema" } ]
soap.body = { :userName => "User", :password => "password" }
end
do_something_response = client.request :do_something do
soap.input = [ "DoSomething", { :xmlns => "http://some.schema"} ]
soap.body = { :securityToken => start_session_response.to_hash[:start_session_response][:security_token] }
end
This results in XML that looks like:
<?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://some.schema"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<DoSomething xmlns="http://some.schema">
<wsdl:securityToken>
<wsdl:tokenType>sessiontoken</wsdl:tokenType>
<wsdl:token>
.
.
.
</wsdl:token>
</wsdl:securityToken>
</DoSomething>
</env:Body>
</env:Envelope>
Never mind the weird namespace convention (or is that just me) in this XML that is savon doing its thing.
The problem I face is that the tags inside the securitytoken tag all start with a lower case letter where they should be upper case. So <tokenType> and <token> should have been <TokenType> and <Token>.
In my opinion the definition of these tags are all in the WSDL that is used to create the savon client. That definition seems not to be used or used incorrectly.
What can I do to get the correct XML/SOAP message from savon?
For later releases of Savon, you should be able to supply a 'global' option of convert_request_keys_to when you initialize your Savon client:
# In Savon 2
Savon.client wsdl:"http://some.url?wsdl", convert_request_keys_to: :camelcase
According to comments in the source file, it accepts one of :lower_camelcase, :camelcase, :upcase, or :none.
I had a similar problem with Savon and ended up using strings in stead of symbols for my hash keys, you could try something like:
soap.body = { 'TokenType'=> 'some_value', 'Token' => 'some_value' }
Savon uses Gyoku for the conversion of tags I believe. To change the symbol conversion you can insert the following statement:
Gyoku.convert_symbols_to :camelcase # or one of [:none, :lover_camelcase]
hope that helps.

Resources