skwpspace yan pritzker’s home on the web

skwpspace is Yan Pritzker's home on the web

Blog :: Photography :: About Me

TwitterCounter for @skwp

Get the news feed
Get updates by email
Follow me on twitter

hello, i'm yan

This blog is about startups, blogging, Ruby On Rails, virtualization and cloud computing, photography, customer service, marketing, ux and design, git, and lots more.

Top Posts

planypus

I'm the founder of Planypus, the place to share your plans!

cohesiveft

Accessible, manageable, virtualized application stacks ready to download or deploy to the cloud!

flickr

smokingThe old man and the accordionBicycle 6x6Eva 6x6Shaffies 6x6Phone Booth Velvia 6x6WynnStar 6x6

Archives

Contact

Reach me at yan at pritzker.ws

Posted
23 August 2006 @ 8pm

Tagged
RubyOnRails, software

Consuming document literal SOAP webservices with Ruby and ROXML

Ruby support for consuming doclit webservices is still less than stellar. Recently I had the task of integrating a standalone RoR application with a backend Java core login system via webservices. Because of our complex schema, soap4r would not work well for creating the data binding objects. Instead, I discovered a very simple and concise way to do xml binding using ROXML.

These objects are sort of the combination of what you might find in a traditional Java XML binding framework such as JiBX, except in Java you’ll typically write the object and then write an xml mapping file. ROXML feels more like Java annotations, where you write the object which is simultaneously the specification for how to marshall/unmarshall it.

# lang ruby
class LoginReq
include ROXML, Initializable
xml_name "LoginReq"
xml_attribute :xmlns
xml_object :Credentials, Credentials
end

class Credentials
include ROXML, Initializable
xml_name “Credentials”
xml_attribute :UserId
xml_attribute :Password
end

Here’s a really simple login request object with a sub element of Credentials. It’s that simple! Now i’ve got some objects that can read and write xml:

# lang ruby
loginReq = LoginReq.new(:xmlns => NS, :Credentials => Credentials.new(
     :UserId => username, :Password => password) )
xml = loginReq.to_xml.to_s

To make this work with webserivices, all you’ll need to do is wrap the xml generated with some soap headers which can be hardcoded as constants.

# lang ruby
def send_request(xml)
data = SOAP_HEAD + xml + SOAP_FOOT
response = Net::HTTP.start(host, port) {|http| http.post2(path, data,
     {"Content-Type" => "text/xml"}) }
end

On the way back, all you have to do is strip off the soap headers, and then unmarshall the xml back into an object

# lang ruby
response_body = response.strip_soap #this just uses a regex to get rid of the extra soap crud again
loginRsp = LoginRsp.parse(response)

The last piece of magic here is the Initializable module which simply allows you to initialize any class by passing in a hash of its attributes:

# lang ruby
module Initializable
def initialize(options);  options.each{|k,v|  self.send("#{k}=",v) };  end
end

Here are the headers and RE for stripping them

# lang ruby
SOAP_HEAD = %{ <soapenv:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body> }
SOAP_FOOT = %{ </soapenv:Body></soapenv:Envelope> }
XML_RE = /<?xml[^>]+>/
SOAP_ENV_RE = /<w+:Envelope.*><w+:Body>(.*)</w+:Body></w+:Envelope>/

Now this may not be as automatic as generating the objects from wsdl, but on the other hand it allows you to extend your model objects and give them rich functionality along with the included xml binding skills they inherit from ROXML. And for now, this may be the only way to talk to complex webservices, whose wsdl is less than ideal for Soap4R. Enjoy!


4 Comments

Posted by
Ray Grace
20 September 2007 @ 3pm

Used your code and it works a treat, much easier than messing about with wsdl’s


Posted by
Ahsan
7 June 2008 @ 1pm

Hi there,

I’m having the same problems with soap4r (doesn’t play well with the wsdl), so I’m going to try out your solution.

Just one question - Where can I find the Initializable module ?


Posted by
Yan
7 June 2008 @ 4pm

Look in the post above :-) it’s right in themiddle there (second to last codeblock). This code is _old_ though so I make no guarantees. It may have quite easily rotted away while it sat on this blog. I haven’t worked with SOAP in a while :-)


Posted by
Ahsan
8 June 2008 @ 7am

Duh :S - Thanks :)


Leave a Comment

OS X productivity tip: dock as taskbar Encrypted db passwords for Rails with database.yml and erb