Getting Started with SOAP4R

SOAP4R is a Ruby library for accessing Web Services via SOAP. Recently I had a chance to explore SOAP4R. Here's how to get started with it.

Installation

Although Ruby comes with SOAP4R in its standard library, it is not the latest. I recommend using the latest gem (1.5.7 as of this writing). It has one dependency, httpclient >= 2.1.0.

gem install soap4r --include-dependencies

However, if you are running Windows, this will not work. The 1.5.7 gem install doesn't properly supercede the built-in library. You must download and extract the .zip file and run 'ruby install.rb'.

Usage

There are two primary ways to use SOAP4R:

  1. Have SOAP4R read the WSDL at run-time and create methods on the fly for you to use. This uses ruby metaprogramming to create ruby methods with the same name as WSDL actions.
  2. Run ‘wsdl2ruby’ which generates a set of classes with which you can call the service. Then 'require' the class representing the service and call its methods. This is the way it is done in most other languages (e.g. Java, C#)

Let’s explore these further.

Method 1: Read the WSDL at run-time

 
require "soap/wsdlDriver"
wsdl = "http://hostname.com/path/to/wsdl"
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
 

A single call to a driver factory reads the WSDL file, and creates a driver class for you to use, complete with the methods defined by the service. What if your service requires authentication? The driver inherits methods from httpclient, so you can specify its options as you would for httpclient:

 
user = "admin"
pass = "xxxxx"
driver.options["protocol.http.basic_auth"] << [wsdl,user,pass]
 

Now you can use the driver to call your web service. Here is a complete example, using the SOAP API for Lyris Listmanager, a mailing-list server, to print the name of all lists:

 
# Create Lyris Driver
require "soap/wsdlDriver"
wsdl = "http://lyris:82/?wsdl"
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
 
# Add authentication
user = "admin"
pass = "xxxxx"
driver.options["protocol.http.basic_auth"] << [wsdl,user,pass]
 
# Print the name of all lists (empty params = return all lists)
lists = driver.selectLists('','')
for list in lists
  puts list.listName
end
 

Notice I called the selectLists method. How do you know what methods you can call? Well, nothing beats good API documentation, because there may be nuances to the API that a WSDL cannot specify, such as the case above where empty params means return all lists. Nevertheless, there are other ways to glean the calling information. For example, you can see the methods by looking at driver.methods in irb. For more information, you can always go to the source and read the WSDL file. But another thing you can do is generate a sample client (see below) which will have an example for each service method, showing you how to call it.

Method 2: Generate classes from WSDL

SOAP4R installs a command-line utility called 'wsdl2ruby' which can generate a client or server. Let's generate a client for the ListManager API (LMAPI). We need to specify the '--wsdl' parameter and '--type client'.

c:> wsdl2ruby --wsdl http://lyris:82/?wsdl --type client
INFO -- app: Creating file 'lmapi.rb'
INFO -- app: Creating file 'lmapiMappingRegistry.rb'
INFO -- app: Creating file 'lmapiDriver.rb'
INFO -- app: Creating file 'lmapiClient.rb'

Note that the generator found the name of the service (LMAPI) in the WSDL and generated a few files:

  • lmapi.rb: defines classes for each SOAP data structure defined in the WSDL (with accessors for convenient access to their properties)
  • lmapiMappingRegistry.rb: maps data model <-> XML instance
  • lmapiDriver.rb: the main class used by your client program.
  • lmapiClient.rb: a sample client program that documents all methods.

These files are interesting to inspect, particularly the sample client program. But the only one you need to require from your program is the xxxDriver.rb module. Let’s revisit the ListManager API example above, this time using the generated driver class:

 
require "lmapiDriver.rb"
driver = LmapiSoap.new
 
#Add authentication
wsdl = "http://lyris:82/?wsdl"
user = "admin"
pass = "xxxxx"
driver.options["protocol.http.basic_auth"] << [wsdl,user,pass]
 
# Print the name of all lists
lists = driver.selectLists('','')
lists.each { |list| puts list.listName }
 

It looks nearly identical. However, we can take this a bit further. Since we have generated files that are specific to accessing a particular service, and the authentication is also specific to the service, we can move the authentication into the driver. If we do this, our client program becomes:

require "lmapiDriver.rb"
driver = LmapiSoap.new

lists = driver.selectLists('','')
lists.each { |list| puts list.listName }

Pretty simple, isn't it?

So which method is best? It probably depends on the situation. Method 1 may be better for development or testing a SOAP server, because it can accommodate changes in the WSDL. It also doesn't require any additional class files. Method 2 may be better when you are creating an interface to an existing, stable SOAP service. It should be slightly faster because it doesn't have to fetch and parse the WSDL (it was already done at code generation time). The driver can also be modified to add authentication or other service-specific things, making the client code simpler.

I’m looking forward to exploring SOAP4R in greater detail.

21 comments ↓

#1 Nome do Jogo » Blog Archive » Acesse Web-Services facilmente com o SOAP4R on 09.15.07 at 8:35 pm

[…] Para entender como funciona, clique aqui. […]

#2 » links for 2007-09-17 [ joseluizcoe.com ] on 09.17.07 at 11:24 am

[…] Getting Started with SOAP4R — Quick off the Mark (tags: webservice rails) […]

#3 napyfab:blog» Blog Archive » links for 2007-09-17 on 09.17.07 at 7:37 pm

[…] Getting Started with SOAP4R — Quick off the Mark (tags: ruby webservices soap soap4r library programming rubyonrails rails framework web development) […]

#4 GSIY … Ruby-Rails Portal on 09.19.07 at 3:25 am

[…] Never gotten familiar with Ruby’s abilities with SOAP? Mark Thomas has put together a really tight beginner’s tutorial to the SOAP4R library. […]

#5 Senthil Nayagam on 09.19.07 at 8:17 am

I am not at all impressed with soap4r, especially post invention of rails.

library is not well maintained, crashes randomly, gem install fails(as you mentioned). uses http-access2 , which has its own ways of raising exceptions.

I have worked on soap4r in 3 occassions and it has left a bitter taste in me.

thats one reason we are promoting REST and other protocols wherever possible. but interfcing with .net and Java app we dont have a alternative.

if you dont agree, will suggest to write a small soap4r script and run it on cron, and get your mailbox of exception notifications

#6 Mark Thomas on 09.19.07 at 2:16 pm

Senthil,

My guess is you haven’t tried it recently. It did experience growing pains in the past but I find the latest version to be stable. It no longer uses ‘http-access2′, which it has replaced with the superior ‘httpclient’.

#7 Dave Peterson on 09.20.07 at 1:02 am

I feel I just have to respond to the earlier criticism of soap4r. I am in the process of using soap4r right now to bind to a particularly complex set of web services written in ASP.NET. Whilst REST integration and simple XML/HTTP approaches certainly have their place, when it comes to integrating a Ruby application with a large 3rd-party application, often SOAP is the only choice.

In integrating with the remote service, I came across a number of limitations of the remote-end implementation, including some very restrictive requirements for namespace representation, and a non-standards compliant mis-handling of the mustUnderstand SOAP header attribute.

In each case, working with the author (NaHi) on the soap4r mailing list, we were able to develop fixes or enhancements to soap4r which he pushed immediately into the head version of the tool. As a result, my web service invocations are now working successfully.

I have found the maintainers to be responsive and the tool to be robust and reliable. I can’t comment on the experience of other users but I just felt the need to provide a contrasting opinion.

One area where soap4r is still lacking is in the documentation department. Tutorials like this are a great start - thanks Mark.

#8 tyler rooney on 09.20.07 at 1:39 pm

great write up.

The demo code and test cases in soap4r 1.5.7 are actually pretty useful. Though, yes, there’s very little documentation.

On that note, make sure you get the latest version of soap4r (which is 1.5.7). Ruby 1.8.6 ships with soap4r 1.5.5 and NaHi has done a ton of fixes since that release.

One tip I’ve found useful when using wsdl2ruby (especially for a rails project) is to add a module name (–module_path [Module::Path::Name]). I’ve used some huge wsdls before and it doesn’t take long before you get a naming collision.

After that, try to avoid using soap if at all possible. seriously.

#9 getting started with soap4r — award tour on 09.20.07 at 1:43 pm

[…] Getting Started with SOAP4R. a good intro for ruby’s standard soap library. also, don’t use soap unless you absolutely have to. […]

#10 Luke Stark on 09.28.07 at 9:13 am

We’re experimenting with soap4r as well, and have found significant problems with memory leaks when retrieving large data sets. This may be our apps, or soap4r or Ruby itself and we’re actively triaging to find out, but I’d love to get any feedback from anyone else using it to pull big data sets.

#11 Coletânea de Links | Blog do Urubatan on 09.29.07 at 10:18 am

[…] Escrever web services com o Rails é muito fácil! Mas tem muita gente que não sabe como acessar eles, então segue este link sobre como acessar WebServices a partir do código Ruby! […]

#12 Mark Thomas on 09.29.07 at 8:21 pm

Version 1.5.8 (release notes) has been released with many, many bugfixes. If anyone has a chance to try the gem install on Windows let me know if it has been fixed.

#13 Ty on 10.04.07 at 2:18 pm

tried the gem install….works now

#14 Adam Bardsley on 10.11.07 at 6:15 am

Is there anyway to allow proxy use to get the WSDL with a factory. I had to get it in advance and then load it locally which was a bit of a pain. Nicve to have a good tutorial in the mix now

#15 Mark Thomas on 10.13.07 at 3:12 pm

@Adam: Sure. Both methods honor the HTTP_PROXY environment variable. See this thread for details.

#16 rascunho » Blog Archive » links for 2007-11-19 on 11.19.07 at 4:23 pm

[…] Getting Started with SOAP4R — Quick off the Mark SOAP4R is a Ruby library for accessing Web Services via SOAP. Recently I had a chance to explore SOAP4R. Here’s how to get started with it. (tags: markthomas.org 2007 mes10 dia19 at_tecp SOAP Ruby) […]

#17 aaa on 11.21.07 at 11:04 am

I wants to put as result players with odds thanks to Betfair API. I try all but I don’t arrive.Please help me …

#18 Mark’s Link Blog » links for 2007-11-23 on 11.23.07 at 2:23 am

[…] Getting Started with SOAP4R — Quick off the Mark (tags: ruby SOAP WebServices soap4r tutorial) […]

#19 Jason Shao on 01.06.08 at 1:47 am

This tutorial was great — gave me a good leg up in writing some glue around some webservices. Thanks.

#20 rubine on 03.11.08 at 9:33 am

I managed to create ruby coding out of a wsdl by using wsdl2ruby. However, I don’t know how to implement the functions of my service now. Can someone help me or know a good tutorial about it?
Thanks in advance!

#21 Mark Thomas on 03.14.08 at 10:15 pm

@rubine:

Please look at the generated Client.rb file. It should have an example for every service method.

Leave a Comment