GAVO Data Center -- SOAP hints

Introduction

SOAP is a protocol for doing remote procedure calls. The idea is that a library on your machine shows a service on our side as if it were a function on yours.

To do this, the library has to know about the arguments and return value(s) of the service. A popular way to convey this information has the nice name WSDL.

We expose some of our services via SOAP. If you need SOAP on a service that does not yet have it, let us know, it's usually just a matter of switching it on.

Both SOAP and WSDL try to solve lots of problems, which has made them quite ugly and unwieldy; you will probably want to steer clear of the details as much as possible. Still, many of the alternatives are even worse, and there are quite a few SOAP implementations around. Some of them even cover significant portions of the standard and work, so it's not as bad as it may sound.

Finding out about SOAP services

On the service info pages, you can see if a SOAP interface is enabled on the service in the renderer paragraph under Overview. See times service as an example. The interface is listed together with a link to the WSDL (that is intended for your library) and half a simple function signature.

A function signature gives the arguments a function takes and its return values. The half that is given describes the arguments in pairs of name and type. The type names are more or less taken from SQL with some extensions, and it should usually be guessable how that maps to your language's types. An exception is anything that starts with vexpr. These are Vizier-like expressions as explained in the docs and are always passed in as strings.

Arguments printed in bold are required, the others optional.

The second part of the signature is the return value. This is, for our service, almost always a list of structures (or records, or whatever it's called in your language). The content of this structure is defined in the Default Output Fields section of the service info (and, of course, also in the WSDL, but you don't want to look at that).

An Example

All this sounds terribly complicated, but in reality accessing SOAP services can be quite simple. The following example is based on the times service above, python and the SOAPy library (that you'll need to install -- on Debian derivatives, it is available as a package python-soappy).

To call a SOAP service via SOAPy, you need to create a proxy with the WSDL. This can look like this:

proxy = SOAPpy.WSDL.Proxy(urllib.urlopen(wsdlURL).read())

This proxy lets you call the various functions defined in the WSDL. In our case, there is always one function called useService. If you have a look at the signature of the times service, you see that all arguments are optional, so let's just see what happens, using the following program:

import urllib
import SOAPpy.WSDL

wsdlURL = "http://vo.uni-hd.de/apfs/times/q/soap/?wsdl"
proxy = SOAPpy.WSDL.Proxy(urllib.urlopen(wsdlURL).read())
print proxy.useService()

This program should produce something like

<SOAPpy.Types.structType outRow at -1216979284>: {'gmst': (0, 10, 50.0), 'ut1': (2008, 10, 10, 9, 33, 1.0), 'gast': (0, 10, 50.0), 'era': 162.501566}

If you know a little Python, you can already guess that you got something like a dictionary here. Let's try it by replacing the last line of the script with

print proxy.useService()['era']

Indeed, the script prints the current earth rotation angle. (Note that due to network latencies and other factors, the "current" figures cannot be used for high-precision work -- for that, you'll most certainly need a local clock).

Now let's try what happens if we get back more than one row (see the service documentation to learn what those arguments actually mean); change the last line in the script to

print proxy.useService(ut1="2008-10-04 .. 2008-10-05")

I recommend to always use keyword arguments ("ut1=...") rather than positional ones. The keywords give some hints as to what the arguments may mean. Positional arguments can, once you forget about the service info page, only be identified from the WSDL, and that's a huge pain. Anyway, the result looks somewhat like this (line broken for display):

[<SOAPpy.Types.structType outRow at -1217044820>: {'gmst': (0, 0, 
52.0), 'ut1': (2008, 10, 4, 0, 0, 0.0), 'gast': (0, 0, 52.0), 'er
a': 12.941522000000001}, <SOAPpy.Types.structType outRow...

So -- you get a list of the dictionary-like objects (this is a bit of a pain with SOAPy, because it's not always easy to predict how many matches will come back -- ah well).

Finally, so see how such a thing could look in a real program, here's one that shows a large ERA clock, updated every 10 seconds from our server:

import Tkinter
import urllib
import SOAPpy.WSDL


class Bigclock(Tkinter.Tk):
	def __init__(self, timegetter):
		Tkinter.Tk.__init__(self)
		self.timegetter = timegetter
		self.clocklabel = Tkinter.Label(self, font=("Helvetica", 200))
		self.clocklabel.pack(expand=1, fill=Tkinter.BOTH)
		self.updateDisplay()
	
	def updateDisplay(self):
		self.clocklabel.config(text=self.timegetter())
		self.after(10000, self.updateDisplay)


def main():
	wsdlURL = "http://vo.uni-hd.de/apfs/times/q/soap/?wsdl"
	proxy = SOAPpy.WSDL.Proxy(urllib.urlopen(wsdlURL).read())
	def timegetter():
		return "%.2f"%proxy.useService()['era']
	b = Bigclock(timegetter)
	b.mainloop()


if __name__=="__main__":
	main()