This is yet another example of an XML-RPC capable web service. Where this example is different though, is that the service can be accessed at the same time using the SOAP protocol. Confusion is avoided by clients for each protocol using different URLs to access the service.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
# The actual web service. import netsvc import netsvc.xmlrpc import netsvc.soap import signal import dbm class Database(netsvc.Service): def __init__(self,name): netsvc.Service.__init__(self,name) self._db = dbm.open(name,'c') self.exportMethod(self.get) self.exportMethod(self.put) self.exportMethod(self.keys) self.joinGroup("web-services") def get(self,key): return self._db[key] def put(self,key,value): self._db[key] = value def keys(self): return self._db.keys() dispatcher = netsvc.Dispatcher() dispatcher.monitor(signal.SIGINT) httpd = netsvc.HttpDaemon(8000) database = Database("test") rpcgw1 = netsvc.xmlrpc.RpcGateway("web-services") httpd.attach("/xmlrpc/database",rpcgw1) rpcgw2 = netsvc.soap.RpcGateway("web-services") httpd.attach("/soap/database",rpcgw2) httpd.start() dispatcher.run() # An XML-RPC client using PythonWare "xmlrpclib" module. import xmlrpclib url = "http://localhost:8000/xmlrpc/database/test" service = xmlrpclib.Server(url) for i in range(10): service.put(str(i),str(i*i)) for key in service.keys(): print key,service.get(key) # A SOAP client using pywebsvcs "SOAP" module. import SOAP url = "http://localhost:8000/soap/database/test" service = SOAP.SOAPProxy(url) for i in range(10): service.put(str(i),str(i*i)) for key in service.keys(): print key,service.get(key)
An ability to support both RPC over HTTP protocols at the same time avoids the question of which to use. A single implementation of the service need only be written. If one protocol wins out over the other, you haven't wasted any time as you simply don't include the gateway for the protocol you don't want to support. It also allows users much more choice in the client implementations which they have available.
Issues which arise in going down this road are that since XML-RPC only supports positional parameters and not named parameters, you are reduced to using only positional parameters through the SOAP interface as well. There is also the problem that XML-RPC doesn't support the Python None type, nor various other scalar data types that can be used with SOAP, eg., extended date and time values. XML-RPC restricts you to using strings as key values in dictionaries which you wish to pass around using the protocol. Worse is that SOAP further dictates what those key values can be. SOAP also can't handle an empty dictionary. Thus, although it may be good to support both protocols, you are forced to use a set of data types and values which will work with both.
The "netsvc" module used by this example comes with OSE which can be found at:
The package provides quite a significant framework for building distributed applications of which the example represents only a small portion. The package comes with its own XML-RPC protocol implementations, but for SOAP currently relies upon the "ZSI" package from the "pywebsvcs" project. This package as well as the "SOAP" client module can be found at: