Savon vs. Handsoap: Calling a service

This documentation is deprecated, please have a look at savonrb.com!

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

Savon clients are just a kind of wrapper or proxy around a WSDL:

client = Savon::Client.new "some_wsdl"

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.

The proxy style client of Savon is less code and provides a flexible API, especially looking at SOAP calls.

Using rspec 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

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 providing a blz (bank code) parameter and extracting the plz (zip code) value of the response.

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

The bank code parameter is assigned in the block, which yields a SOAP message object. 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, ruby-libxml or nokogiri.

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

The block yields a SOAP request object 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.

Published by

phoet

I am a professional Software Developer from Hamburg, Germany.

One thought on “Savon vs. Handsoap: Calling a service”

Comments are closed.