This documentation is deprecated, please have a look at “savonrb.com”:http://savonrb.com/!
p. The two libraries have different approaches on how to get things done. While Handsoap is using an oldschool inheritance style definition:
class HandsoapBankCode < Handsoap::Service
endpoint :uri => "some_wsdl", :version => 2
def on_create_document(doc)
doc.alias "tns", "some_namespace"
end
def on_response_document(doc)
doc.add_namespace "ns1", "some_namespace"
end
[...]
end
p. Savon clients are just a kind of wrapper or proxy around a WSDL:
client = Savon::Client.new "some_wsdl"
p. While inheritance is a base concept of object oriented programming, it’s usually better to use delegation instead. For not being stuck on the API of the Handsoap::Service class, one would wrap things up into some other class or module, creating more code than necessary.
p. The proxy style client of Savon is less code and provides a flexible API, especially looking at SOAP calls.
p. Using “rspec”:http://rspec.info/ to demonstrate the expected behavior of the clients results in two identical spec for getting a zip code of a concrete client implementation:
describe "Savon" do
it "should return the corrent zip code for a given bank" do
zip_code = Shootout::SavonBankCode.zip_code @bank_code
zip_code.should eql @zip_code
end
end
describe "Handsoap" do
it "should return the corrent zip code for a given bank" do
zip_code = Shootout::HandsoapBankCode.zip_code @bank_code
zip_code.should eql @zip_code
end
end
p. Compared to the spec, the code of the two implementations differs a great deal. The task at hand is to call the getBank method of the “SOAP endpoint”:http://www.thomas-bayer.com/axis2/services/BLZService?wsdl providing a blz (bank code) parameter and extracting the plz (zip code) value of the response.
p. Using the Handsoap client class defined above, sending the “invoke()” message to the Handsoap::Service will do the job:
def zip_code(bank_code)
response = invoke("tns:getBank") do |message|
message.add "tns:blz", bank_code
end
(response/"//ns1:details/ns1:plz").first.to_s
end
p. The bank code parameter is assigned in the block, which yields a “SOAP message object”:http://github.com/unwire/handsoap/blob/master/lib/handsoap/xml_mason.rb. The resulting XML document is wrapped and can be accessed using some predefined XML library. Handsoap enables you to choose between different types of XML parsers like “REXML”:http://www.ruby-doc.org/core/classes/REXML.html, “ruby-libxml”:http://libxml.rubyforge.org/ or “nokogiri”:http://github.com/tenderlove/nokogiri.
p. Savon’s proxy client on the other hand is dynamic and can be accessed directly with the name of the SOAP method and a block:
class SavonBankCode
def self.zip_code(bank_code)
client = Savon::Client.new Shootout.endpoints[:bank_code][:uri]
response = client.get_bank { |soap| soap.body = { "wsdl:blz" => bank_code } }
response.to_hash[:get_bank_response][:details][:plz]
end
end
p. The block yields a “SOAP request object”:http://github.com/rubiii/savon/blob/master/lib/savon/soap.rb for setting the payload or tweaking defaults like the SOAP header. Converting the response to a hash is a convenient way to access the desired result. The conversion is done using “crack”:http://github.com/jnunemaker/crack/.
Pingback: Savon Handsoap Shootout | #nofail