Home > Technology > Making Soap Requests with Ruby (on Rails even)

Making Soap Requests with Ruby (on Rails even)

If you want to interact with another web-service on the inter-webs as we know it, sooner or later you will find the need to make a SOAP call using Ruby.

Today I ran into such a need.

I looked at a few things already out there that could do it, but for the most part, it was overkill.

So I tried to figure out how to roll my own, and this is what I found ::


First, I saw this post that seems to be the easiest way to roll your own

I ran into errors ::

/usr/lib/ruby/1.8/net/http.rb:560:in `initialize': getaddrinfo: Name or service not known (SocketError)

Hmm, Name or Service not known, and the error pointed to this line in the code

resp, data = http.post(path, data, headers)

So all my Ruby code worked, but that failed.

So I looked a little deeper, and found this email exchange

Ah, ok, so I tried that – parsed out the URL I was attempting to hit, and then went for it.

Got a new error

/usr/lib/ruby/1.8/net/http.rb:560:in `initialize': getaddrinfo: Servname not supported for ai_socktype (SocketError)

This was the result of a silly mistake of mine wherein for the Headers section I had the following

headers = {
'Referer' => 'http://www.brickfactor.net',
'Content-Type' => 'text/xml',
'Host' => 'https://www.site.co.uk/some_path/to_some_file.pl'
}

The way it needed to look was

headers = {
'Referer' => 'http://www.brickfactor.net',
'Content-Type' => 'text/xml',
'Host' => 'www.site.co.uk'
}

Ah wonderful – let’s hit it again, and see what happens.

Code = 400
Message = Bad Request
connection = close
content-type = text/html; charset=iso-8859-1
date = Mon, 17 Aug 2009 22:24:45 GMT
server = Apache/2.2.3 (CentOS)
content-length = 323
<h1>Bad Request</h1>
Your browser sent a request that this server could not understand.
<hr />
<address>Apache/2.2.3 (CentOS) Server at https://www.site.co.uk Port 443</address>

New error, but this time – atleast it was from the server at the other end. So I’d made a connection, but the server didn’t understand me (ah – story of my life you say? Well, you too might need a SOAPAction)

So I went digging deeper. Adding this line to the Headers section, made it work.

'SOAPAction' =&gt; 'https://www.site.co.uk/NAMESPACE1#METHOD_NAME'

Technically SOAPAction is supposed to match uri#method I believe, the above is just what worked for me.

Obviously, if there is an easier way, I’m very very interested.

The final code looks like this
require 'net/http'
require 'net/https'
require 'uri'
# Create the http object
url = "https://www.site.co.uk/some_path/to_some_file.pl"
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if (uri.scheme == 'https')
# Create the SOAP Envelope
data = &lt;&lt;-EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="https://www.site.co.uk/NAMESPACE"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:stock_qty>
<param0 xsi:type="xsd:string">API_KEY</param0>
<param1 xsi:type="xsd:int">INTEGER</param1></ns1:stock_qty>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
EOF
# Set Headers
headers = {
'Referer' =&gt; 'http://www.brickfactor.net',
'Content-Type' =&gt; 'text/xml',
'Host' =&gt; 'www.site.co.uk',
'SOAPAction' =&gt; 'https://www.site.co.uk/NAMESPACE#METHOD'
}
# Post the request
resp, data = http.post(uri.path, data, headers)
# Output the results
puts 'Code = ' + resp.code
puts 'Message = ' + resp.message
resp.each { |key, val| puts key + ' = ' + val }
puts data

Categories: Technology Tags: , ,
  • Pau

    Thanks! You saved my life!

  • http://dragonsbehere.com/ Akshay

    Hah – glad to have been helpful.