Using Emacs & restclient.el with SOAP services

Recently I’ve been using the handy restclient.el for testing/investigating a SOAP service. It’s not really designed for this, so I wanted to make notes on a couple of quirks.

WSSE authentication

This particular service requires every request to have an authentication “header” element inside the XML document for each request. This is quite unlike the usual restclient examples of bearer tokens in HTTP headers. A typical request document’s <soapenv:Header> contains this:

<wsse:Security xmlns:wsse="long1.xsd" xmlns:wsu="long2.xsd">
  <wsse:UsernameToken>
    <wsse:Username>AzureDiamond</wsse:Username>
    <wsse:Password>hunter2</wsse:Password>
  </wsse:UsernameToken>
</wsse:Security>

(Note: the longN.xsd URLs are much longer; trimmed for brevity)

I extracted this out to a separate file for the sake of my sanity, and put the following at the top of my restclient scratch file:

# Define the common WSSE authentication for the header
:wsse-security := <<
(progn (with-temp-buffer
       (insert-file-contents "env-wsse-security.xml")
       (buffer-string)))

Making SOAP requests

Because restclient.el is so generic, this is pretty simple once you remember that SOAP just means POSTing XML documents to an endpoint.

  1. Read the WSDL file for the service
  2. Find the definition for the request you want to make
  3. Copy/paste the request into a <soapenv:Body> (check long XSD URLs & namespaces)
  4. POST with content-type text/xml to the endpoint

For instance (using the :wsse-security var defined above):

# Find valid travel dates from Hereford to London
POST https://api.generictravel.co/soap/search/
Content-Type: text/xml

<soapenv:Envelope xmlns:soapenv="long" xmlns:sear="long" xmlns:com="long">
  <soapenv:Header> :wsse-security </soapenv:Header>
  <soapenv:Body>
    <sear:TravelDatesRequest>
      <sear:header>
        <com:version>1.0</com:version>
        <com:retailOperation>GB</com:retailOperation>
        <com:channel>DIGI</com:channel>
      </sear:header>
      <sear:originId>122</sear:originId>
      <sear:destinationId>13</sear:destinationId>
    </sear:TravelDatesRequest>
  </soapenv:Body>
</soapenv:Envelope>

Hitting C-c C-v on that fills the opposite window with XML, which restclient is nice enough to pretty-print and highlight for you. Still, it’s easy to remember why REST and JSON caught on.