Savon vs. Handsoap: Authentication

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

The libraries provide support for multiple authentication protocols. While Handsoap’s authentication support is more low level, Savon provides an API for that task.

WSSE authentication

As you might expect, the Handsoap way for this aspect is to implement a callback method for the document creation. Using Savon you can attach your credentials on a WSSE object inside your request block. Compare the two implementations:

def on_create_document(doc)
  doc.alias 's', "http://docs...xsd"
  header = doc.find("Header")
  header.add "s:Security" do |s|
    s.set_attr "env:mustUnderstand", "0"
    s.add "s:Username", @@username
    [...]
  end
end
response = client.get_bank do |soap, wsse|
  wsse.username = @@username
  [...]
end

HTTP authentication

The same approach is used by Handsoap to offer HTTP authentication:

def on_after_create_http_request(http_request)
  http_request.set_auth @@username, @@password
end

Savon provides support for this feature just yet (since 0.7.0):

client.request.basic_auth "username", "password"

SSL support

At the time of writing only Savon supports SSL authentication directly. This is achieved by passing a configuration hash to the Savon::Client:

client = Savon::Client.new "some_wsdl"
client.request.http.ssl_client_auth(
  :cert => OpenSSL::X509::Certificate.new(File.read("client_cert.pem")),
  :key => OpenSSL::PKey::RSA.new(File.read("client_key.pem"), "password if one exists"),
  :ca_file => "cacert.pem",
  :verify_mode => OpenSSL::SSL::VERIFY_PEER
)

While the Handsoap documentation states that support for SSL is not yet implemented, there might be a chance to enable it through the use of the preconfigured http driver.

Savon vs. Handsoap: Errors

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

Both client libraries provide the same default behavior for error handling; they raise distinct exceptions for SOAP and HTTP errors:

  • Handsoap::HttpError / Handsoap::Fault
  • Savon::HTTPError / Savon::SOAPFault

And both clients offer a way to override that behavior. Savon lets you surpress errors globally and provides a simple error handling interface on the response object:

Savon::Response.raise_errors = false
[...]
p response.soap_fault
p response.http_error

The same can be achieved in Handsoap by overwriting error hooks in the service implementation:

def on_fault(fault)
  p fault
end

def on_http_error(response)
  p response
end

Savon vs. Handsoap: Benchmark

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

As every benchmark is only as good as the platform it is performed on, you should execute them on your own machine. The example code provides a rake task for that. Running the benchmarks on a local development machine (MacBook 2.4GH Intel Core 2 Duo) produces the following results:

$ rake benchmark
                                    user     system      total        real
savon dynamic                   0.390000   0.070000   0.460000 ( 17.860459)
savon static                    0.120000   0.040000   0.160000 ( 11.929432)
handsoap                        0.100000   0.020000   0.120000 (  3.962274)
[...]

Since Handsoap uses native C libraries like curb and nokogiri the produced results are not that surprising. Savon on the other hand is based on pure Ruby with only a small set of dependencies.

Handsoap offers a way to change the underlying gems for HTTP connectivity and XML parsing. There are some more benchmarks for these configurations:

[...]
                                    user     system      total        real
handsoap curb nokogiri          0.100000   0.020000   0.120000 (  3.962274)
handsoap curb rexml             0.080000   0.040000   0.120000 (  3.905696)
handsoap curb libxml            0.060000   0.040000   0.100000 (  8.961743)
handsoap net_http nokogiri      0.130000   0.050000   0.180000 (  9.184230)
handsoap net_http rexml         0.100000   0.050000   0.150000 ( 11.429074)
handsoap net_http libxml        0.070000   0.050000   0.120000 (  9.220251)
handsoap httpclient nokogiri    0.310000   0.040000   0.350000 (  4.381711)
handsoap httpclient rexml       0.430000   0.070000   0.500000 (  4.782451)
handsoap httpclient libxml      0.350000   0.040000   0.390000 (  4.209751)

Savon vs. Handsoap: JRuby

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

First of all, both client implementations can be run using JRuby. Since Savon is a pure Ruby implementation you get JRuby support for free. The drawback is, that it’s slow on MRI.
Using native C Libraries by default, Handsoap is bleezing fast. But when it comes to terms of compatibility with JRuby you’ve got to fall back to slow core Ruby classes:

Handsoap.http_driver = :net_http
Handsoap.xml_query_driver = :rexml

Using this configuration nearly elimininates the differences in performance:

$ rake benchmark_jruby
                                    user     system      total        real
savon jruby dynamic            15.060000   0.000000  15.060000 ( 15.060000)
savon jruby static             10.984000   0.000000  10.984000 ( 10.984000)
handsoap jruby                  8.717000   0.000000   8.717000 (  8.717000)

Savon vs. Handsoap: Conclusion

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

The dynamic coding style of Savon is more elegant and the Ruby magic makes it easy to use. Integrating SOAP services is now a fun task!

Handsoap makes a good job on encapsulating SOAP calls and provides a wide spectrum of configuration points. It’s very fast on MRI and you have complete control over the XML and transport layer.

Even though I am a Java guy I love the Savon approach to SOAP, especially because it completely eliminates the XML part!

Many thanx to rubiii for helping with the examples.