A Web Services Epiphany – Accessing Confluence from F# Using SOAP

Web services” has been a buzz word for so long you might wonder if there’s any buzz left. I’d known in principle about how web service technology was full of goodness, especially for achieving interoperability, but I’d never really taken the red pill. However, recently I had an epiphany.
I’ve been working in a team using the Confluence wiki to organise some information. Confluence is a page-based wiki, but I’ve been pushing it a little in the direction of being a semantic wiki, by using 2-column tables on some pages, to represent key-value pairs for page attributes and relationships. My problem was that, to Confluence, those tables were just ordinary textual content. There was no way to check that the special tables were well-formed, and there was no way to query the wiki using the page attributes and relationships.
My first plan was to export the wiki to XML and query that, but then I discovered that Confluence has a SOAP API. It looked promising, and it also looked like a good excuse to do some more scripting with F#.
I bumbled around the web looking for simple guide on how to actually use SOAP, and finally came across a page from Robert Pickering’s site that laid it all out for me. For Confluence, it goes like this:

  1. Generate a C# file from the Confluence WSDL file:
    wsdl http://<your-confluence-path-here>/rpc/soap-axis/confluenceservice-v1?wsdl
  2. Compile it to produce a dll:
    csc /target:library ConfluenceSoapServiceService.cs

(My wsdl.exe is in C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin, and my csc.exe is in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727, but yours might be somewhere else.)
Then you’re set to go. For the purposes of exposition, say you want a page called “PAGE” from a Confluence space called “SPACE”, to which you’ve got anonymous access:

  1. In the F# interactive environment, load the dll, e.g. :
    #r "ConfluenceSoapServiceService.dll"
  2. Then, create a new type F# object to expose that SOAP API:
    let wiki = new ConfluenceSoapServiceService()

    (Right now, in the interactive environment, I need to call this twice to get it to work, because of some strange F# interactive bug, but Don assures me it works first time when it’s compiled.)

  3. The API functions are available as members of that new object, just like they were written natively in F#:
    let page = wiki.getPage("", "SPACE", "PAGE")
  4. But it’s not just the API functions – the values too are all just like they were written natively in F#. For example, the page returned above is in the RemotePage type. It has fields for things such as the page content:
    page.content

After that I was away – the standard libraries and seamless .net interoperability provided by F# made most things easy. The hardest part of the exercise was working out how to parse the Confluence wikicode using regexes. (Oh, the pain!)
So, now I’ve seen the light – web services really are ace. I was accessing an API implemented in Java, running on *nix, but to me it looked like it was native to F#, running on Windows. And setting it up took almost no effort. (After I found out how it was done. 🙂 )
I think my epiphany was mostly about web services, or was it about F#?

Comments 4