Building legacy SOAP APIs in Ruby on Rails
I’ve already consumed some SOAP web-services in ruby using savon and as expected it wasn’t the dreamworld for a rails-dev. Perhaps some Java or .NET developers love to generate connector-code for webservices from the WSDL with all that IDE integration and autocomplete-features but as ruby developer you just want use a simple, lightweight, restfull API instead.
Rails and SOAP actually doesn’t fit very well together but sometimes it’s also necessary to provide an oldschool SOAP webservice. E.g. when the customer has multiple systems talking to an existing service and just want to switch to your system without changing their whole implementations.
In this article I want to talk about a gem I’ve found that takes away some pain from you and allow to define SOAP methods directly in your rails controller. It’s called wash_out – man, how I love these ironic names ;-)
Let’s say we want to create a simple webservice that allows to calculate the FizzBuzz value of a number. In this case we’d need one method that gets an integer as an input parameter and also returns one – very simple but a nice example:
int getFizzBuzz(int number)
Accordning to this requirement the rails controller could look like the following:
# just a normal rails controller class FizzBuzzController < ApplicationController # define a custom soap namespace (optional) soap_service namespace: 'urn:FizzBuzz' # define the method we want to provide with # its signature and map it to a controller action soap_action 'getFizzBuzz', args: :integer, return: :string, to: :get_fizz_buzz # the actual implementation as standard rails action # raising a special exception type if parameters are missing # and rendering a soap response directly from the ruby datatypes def get_fizz_buzz raise SOAPError, "parameter value is missing!" if params[:value].nil? render soap: fizz_buzz(params[:value]) end private # just a simple helper method to do the actual "calculation" def fizz_buzz(number) return 'Fizz' if number % 3 == 0 return 'Buzz' if number % 5 == 0 number end end
The SOAP enabled controller needs a special declaration in the routes.rb file:
Rails.application.routes.draw do wash_out :fizz_buzz end
require 'spec_helper' describe 'SOAP actions' do describe 'getFizzBuzz' do it 'returns the number back' do post '/fizz_buzz/action', <<-SOAP <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:FizzBuzz"> <soapenv:Header/> <soapenv:Body> <urn:getFizzBuzz soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <value xsi:type="xsd:int">23</value> </urn:getFizzBuzz> </soapenv:Body> </soapenv:Envelope> SOAP expect(response).to_not be_error expect(response.body).to include '<value xsi:type="xsd:string">23</value>' end # [...] end end
As you can see the gem allows to easily integrate the SOAP technology into a standard rails development workflow. Have fun but as also the readme of the gem tells us:
If you have a chance, try to avoid using SOAP.