block in a soap4r request Comments Feed" href="/"/>

How to include a block in a soap4r request

Here at Blazing Cloud we recently had to write some Ruby code to integrate with an external service via. SOAP. I cringed a little at the thought of working with SOAP, but I was pleased to find that the soap4r gem is fairly easy to use and works pretty well. Getting Started with SOAP4R is a nice tutorial that gave us most of the information we needed to get things working.

We did run into a gotcha that was tricky to solve. Our SOAP service required an authentication ticket to be sent with every request, and the format of this ticket required it to contain a <![CDATA[… ]]> block. We had to do a bit of finagling to convince the soap4r XML builder not to escape the < and > characters. Extensive searching on the interwebs told us that many others had run into the same problem, and nobody seemed to know how to solve it. But we were not to be discouraged! Nay, we persevered and found a simple solution that involves the use of a custom HeaderHandler. The use of HeaderHandlers in soap4r is well documented already in many articles so I won’t go into the details here. I will only discuss the steps required to send the <![CDATA[… ]]> block

Here is the general format required for our request header in our SOAP request (excluding the service details):

<soapenv:Header>
    <AuthTicket>
        < Value><![CDATA[blah blah blah here is the value]]></ Value>
    </AuthTicket>
</soapenv:Header>

And here is the code in our HeaderHandler that resulted in the desired header format:

class HeaderHandler < SOAP::Header::Handler
  def initialize(auth_ticket)
    @auth_ticket = auth_ticket
    super(XSD::QName.new)
  end
  def on_outbound
    raw_str = SOAP::SOAPRawString.new("<![CDATA[#{@auth_ticket}]]>")
    raw_str.elename = XSD::QName.new('http://www.someservice.com/ApiService', 'Value')
    auth_ticket = SOAP::SOAPElement.new(
          XSD::QName.new('http://www.someservice.com/ApiService', "AuthTicket"))
    auth_ticket.add(raw_str)
    SOAP::SOAPHeaderItem.new(
          auth_ticket, false, SOAP::EncodingStyle::LiteralHandler::Namespace)
  end
end

The two relevant lines of code for including the <![CDATA[… ]]> block are:

The SOAP::SOAPRawString type for the node that holds the value in this line of code:

raw_str = SOAP::SOAPRawString.new("<![CDATA[#{@auth_ticket}]]>")

The SOAP::EncodingStyle::LiteralHandler::Namespace encoding style on the header item in this line of code:

SOAP::SOAPHeaderItem.new(
    auth_ticket, false, SOAP::EncodingStyle::LiteralHandler::Namespace)

That’s it!

2 Comments

  1. Glenn
    Posted May 26, 2010 at 1:34 am | Permalink

    Just perusing your articles and this one is really timely. My current project is just about to integrate with a SOAP service and its nice to have some examples.

    Hope you had a good time at the fundraiser last night too, I know the Pivots had a good time.

  2. Brad
    Posted October 6, 2010 at 10:48 am | Permalink

    A ruby library that works wonders when using SOAP is Savon (used with Nokogiri). Highly recommend you check that out if doing SOAP stuff… Savon is on github ( http://github.com/rubiii/savon ), as is Nokogiri of course.

Post a Comment

Your email is never shared. Required fields are marked *

*
*