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 1.8.x comes with SOAP4R in its standard library, it is an old, buggy version. I highly recommend using the latest gem (1.5.8 as of the this update). It has one dependency, httpclient.
gem install soap4r --include-dependencies
Note that the 1.5.7 gem install didn't properly supercede the built-in library in Windows. You had to download and extract the .zip file and run 'ruby install.rb'. Version 1.5.8 has reportedly fixed this issue.
Usage
There are two primary ways to use SOAP4R:
- 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.
- 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_drive
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 to the 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.
Update: I emphasized my recommendation to install the latest version of soap4r. The source of most of the problems posted in comp.lang.ruby are caused by old versions of soap4r.
32 comments ↓
[...] Para entender como funciona, clique aqui. [...]
[...] Getting Started with SOAP4R — Quick off the Mark (tags: webservice rails) [...]
[...] Getting Started with SOAP4R — Quick off the Mark (tags: ruby webservices soap soap4r library programming rubyonrails rails framework web development) [...]
[...] Never gotten familiar with Ruby’s abilities with SOAP? Mark Thomas has put together a really tight beginner’s tutorial to the SOAP4R library. [...]
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
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’.
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.
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.
[...] Getting Started with SOAP4R. a good intro for ruby’s standard soap library. also, don’t use soap unless you absolutely have to. [...]
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.
[...] 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! [...]
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.
tried the gem install….works now
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
@Adam: Sure. Both methods honor the HTTP_PROXY environment variable. See this thread for details.
[...] 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) [...]
I wants to put as result players with odds thanks to Betfair API. I try all but I don’t arrive.Please help me …
[...] Getting Started with SOAP4R — Quick off the Mark (tags: ruby SOAP WebServices soap4r tutorial) [...]
This tutorial was great — gave me a good leg up in writing some glue around some webservices. Thanks.
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!
@rubine:
Please look at the generated Client.rb file. It should have an example for every service method.
[...] a .NET web service that uses WSSE based authentication. Thanks to the intarweb, I was able to get started with soap4r and insert WSSE authentication headers into my SOAP requests.The samples available on the tracker [...]
has anyone used soap4r to connect to a .net web service under windows auth successfully?
What kind of authentication, specifically, are you talking about? NTLM, LDAP, basic?
Check the SOAP4R mailing list archives. Here’s one thread with some guidance:
http://groups.google.com/group/soap4r/browse_thread/thread/5628a93cfbcd684a/
Hi,
Iam getting this error:
part: requestParams cannot be resolved
Anyone faced this issue?
Iam using 1.5.8 version and the ruby version is 1.8.6
I have installed the gem using gem install soap4r –include-dependencies
My code is
factory = SOAP::WSDLDriverFactory.new(”http://aspire388:8080/ClubConcierge306/axis/LWFlowerService?wsdl”)
driver = factory.create_rpc_driver
Are you sure you have the URL correct? Try a fully qualified domain name.
I’m trying to consume a sopa web service. When I use the wsdl2ruby.rb, I get the following error for this wsdl - http://integration.delivra.com/DelivraServices/MemberService.asmx?WSDL
FATAL — app: Detected an exception. Stopping … duplicated ‘any’ (RuntimeError)
I am able to dynamically use wsdl through the create_rpc_driver classes for the simple methods. I am however having no luck trying to call the more complex methods (like add). Any thoughts?
Hi, Mark.
I was wondering if you could provide an example of how to attache a file (xml, csv, jpg) to a soap request?
I’m completly confused!
@Nick: Sorry, I don’t have an example handy. Attachments, both sent and received, are in multipart MIME format (like email). Take a look at the SOAP::Attachment class to see if you can use it to set or get the attachment body. See also the SOAP attachment standard (http://www.w3.org/TR/SOAP-attachments) if you want more detail on how attachments work.
[...] In Ruby, you can use the soap4r library to create an RPC driver from a WSDL file, like so (as described here): [...]
Do you have an example where you move the authentication into the driver? And do you have an example where you send complex headers…. like:
@accountInfo => [@accountName => 'xxxxx', @accountPassword => 'xxxxxxxxxxxxx']
When I try to pass somthing like this, it only recognizes the 1st paramater.
Just a heads up, might want to do a search and replace to catch an instance of ‘create_rpc_drive’ and replace with ‘create_rpc_driver’. That one had my scratching my head for the last half hour. Thanks for the tutorial!
Leave a Comment