Writing a SOAP web service in Ruby

Ruby 1.9 doesn’t come with SOAP support out of the box, in this article I’ll show you a very basic example SOAP service over HTTP that I’ve written in Ruby 1.9 that supports a subset of the SOAP 1.1 standard (enough to make it compliant for what it does) that you can use to get started if you want or need to write a SOAP service in Ruby get started. Additionally I’ll briefly show you how you can poke around it with soapUI and how you can consume (use) it with PHP, Java (using Apache CXF), .NET and of course Ruby (using Savon).

The SOAP service that I’ve written for this article is the EchoService, it has two operations: Echo and ReverseEcho. Unsurprisingly Echo returns the message the client sent and ReverseEcho returns it reversed. The source is available on GitHub at https://github.com/mkremer/echo_service, go ahead and clone the repository or download the source from there. Have a look around to see how it works and follow the README to get it up and running.

In this article all my examples will show http://localhost:9292/echo_service.wsdl as the WSDL URL, if you’re not running the EchoService locally (but on a server or in a VM) then you have to change the URL appropriately to try the examples. Additionally the WSDL contains the URL to the endpoint, and that URL will in most cases be used automatically. You can set the environmental variable BASE_URL (in more detail described in the EchoService README) to alter the endpoint URL shown in the WSDL.

soapUI

If you have a WSDL for a SOAP service and want to play around with it without having to write code there are some tools that you can use to do just that, a tool I often use for this purpose is soapUI (in this example I used the free open source version).

Once you have the EchoService up and running and you’ve got soapUI installed and started up click on the “File menu” and click on the first option (labelled “New soapUI Project”), this will bring up the following popup:

soapUI new project popup

Enter the details as I have above. Once you click the “OK” it adds a new project named “Echo”. You’ll see the EchoBinding (which represents the service that is specified in the WSDL) and the possible operations. If you expand any of the operations you’ll see that a test request named “Request 1” has been added to each of them. Double clicking on a request will open a new window (within soapUI) in which you can edit the request before sending it by hitting the green play button (in the top left of the request window), the resulting response will be shown in the right split. Below is a screenshot of what soapUI looks like after doing all of the above:

soapUI Echo project

soapUI is a really awesome tool, there’s a lot more to it than I’ve shown here (you can create test suites, use it to run mocked web services based on WSDL files, and more). Its a tool worthwhile adding to your arsenal.

PHP

PHP 5 has SOAP support built in (if PHP has been compiled with –enable-soap), the documentation is available online here: http://www.php.net/manual/en/book.soap.php. Its extremely simple to consume SOAP services using PHP, below is a very brief example:

<?php
  $wsdl = "http://localhost:9292/echo_service.wsdl";
  $client = new SoapClient($wsdl);
  $response = $client->Echo(array("Message" => "Hello from PHP"));
  echo "EchoService responded to Echo: " . $response->Message . "\n";
?>

The above PHP script will output: “EchoService responded to Echo: Hello from PHP”.

If you want a more complete example implementation that includes explanatory comments and basic error handling then you can checkout my project on GitHub: https://github.com/mkremer/echo_service_client_php.

Java

To generate the code required to consume a SOAP service in Java I used the Apache CXF framework. The generated code uses the standard Java API and thus doesn’t have CXF as a runtime dependency. To get it setup up you need to do the following:

  • Install the Java JDK (if you haven’t already – I am using JDK 7), and ensure that the JAVA_HOME environmental variable is set to the path where your JDK is installed
  • Download Apache CXF (for this example I used 2.4.3) and unpack it somewhere appropriate
  • Add /path/to/apache-cxf/bin to your PATH so you can easily use the CXF command line tools without having to spell out the entire path every time

Once that’s all done open a shell, create a new directory, go into it and enter the following command: wsdl2java -client http://localhost:9292/echo_service.wsdl. If all goes well the command gives no output, but it does create a new directory structure with Java files inside:

$ tree
.
└── net
    └── without_brains
        ├── echo
        │   ├── EchoMessageType.java
        │   ├── ObjectFactory.java
        │   └── package-info.java
        └── echo_service
            ├── EchoPortType_EchoPort_Client.java
            ├── EchoPortType.java
            └── EchoService.java  
4 directories, 6 files

The directory structure is a copy of the namespace URL, but in reverse (translating the namespace URI to a Java package name). If you’re using a Java IDE you can copy this entire directory structure into your Java project’s source directory to make use of the generated code.

net/without_brains/echo_service/EchoPortType_EchoPort_Client.java is an example client generated by CXF that calls each of the operations. Note that it won’t work as is, as it sets the Message parameter to null which isn’t allowed. You easily modify it to work properly or use it as a starting point to write your own implementation.

A simple example of using the code generated by CXF:

import net.without_brains.echo_service.*;
import net.without_brains.echo.*;
public class Echo {
  public static void main( String[] args ) throws Exception {
    EchoService client = new EchoService();
    EchoPortType echo = client.getEchoPort();
    EchoMessageType request = new EchoMessageType();
    request.setMessage("Hello from Java");
    EchoMessageType response = echo.echo(request);
    System.out.println("EchoService responded to Echo: " + response.getMessage());
  }
}

If you want an example implementation that includes explanatory comments and basic error handling then you can checkout my project on GitHub: https://github.com/mkremer/echo_service_client_java.

.NET

Consuming SOAP services with .NET is easy as pie through Visual Studio. If you don’t have a license for Visual Studio you can download one of the free versions (called Express editions) here: http://www.microsoft.com/visualstudio/en-us/products/2010-editions/express (I used the Express edition of Visual Studo C# in this example).

Once you have started up Visual Studio go ahead and create a new project, in this example I created a console application:

C# .NET project for a console application

Right click on the “References” entry in the “Solution Explorer” (which is on the right side of the screen) and click on the option “Add Service Reference”. You’ll get a popup like the one shown below:

Adding a new ServiceReference

Enter the details as I have above and click on the OK button.

To make use of EchoService add some code like shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace EchoClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Echo.EchoPortTypeClient client = new Echo.EchoPortTypeClient();
            Echo.EchoMessageType request = new Echo.EchoMessageType();
            request.Message = "Hello from C#";
            Echo.EchoMessageType response = client.Echo(request);
            Console.WriteLine("EchoService responsed to Echo: " + response.Message);
        }
    }
}

Running the above code (you can use the shortcut CTRL+F5) should open a console window with the output: “EchoService responded to Echo: Hello from C#”.

If you want an example implementation that includes explanatory comments and basic error handling then you can checkout my projects on GitHub: https://github.com/mkremer/echo_service_client_csharp for C# and https://github.com/mkremer/echo_service_client_vb for Visual Basic.

Ruby (using Savon)

Consuming SOAP services in Ruby is pretty easy if you use Savon, here’s an example snippet:

client = Savon::Client.new("http://localhost:9292/echo_service.wsdl")
response = client.request :echo, "EchoRequest", :body => { "Message" => "Hello from Ruby" } do
  # The EchoService has its messages in a different namespace than the
  # targetNamespace of the WSDL, specify it here to have the request
  # rendered properly
  soap.namespaces["xmlns:echo"] = "http://www.without-brains.net/echo"
end
data = response.to_array(:echo_response).first
puts "EchoService responded to Echo: #{data[:message]}"

Like I have done for the other programming languages I have created an example implementation with explanatory comments and basic error handling that you can checkout on GitHub: https://github.com/mkremer/echo_service_client_ruby.

If you want an introduction to using Savon you can also watch the Railscast on Savon.

A few more notes on consuming SOAP services

In all of the examples in this article I’ve been pointing to the URL of the WSDL, its often desirable to download a copy of the WSDL (and files that it includes such as XML schema files) to include in your code base and use that instead. There are a two advantages to doing this:

  • You can modify the URL of the endpoint in your local copy to match the endpoint that you’re going to be talking to, negating the need to write code to do that (this can be desirable for any number of reasons).
  • Some of the above examples use the WSDL at runtime, if the WSDL becomes unavailable or if it gets changed it can cause your system to break down (using a local copy will prevent those types of crashes and reduces the amount of error handling required)

If you’re still reading…

You’ve reached the end of my article, thank you for reading it! I’ve spent a considerable amount of time writing this up and writing the example implementations, I hope you’ve enjoyed it all and that it has been of use to you.

Good luck with your SOAP endeavors!

Follow

Get every new post delivered to your Inbox.

Join 155 other followers

%d bloggers like this: