News

2nd December 2014 by aegeuana_sjp_admin

Using SOAP with SUDS – an introduction

I’m sure that most of you reading this post have heard/used the XML/SOAP – same as me.
However I’d never used the WSDL before, yet last week I needed to work with two, unconnected to each other APIs, using this protocol. So I’ve started researching  WSDL and apparently it is the standard protocol for describing API methods of web services.
WSDL stands for Web Services Description Language and is an XML document that uses SOAP to exchange information. It allows you to send requests and receive responses from a remote server. One of the interesting and useful things about this protocol is that it describes the accepted types and methods really precisely. That allows you to easily prepare empty objects (like template) which is formatted in a way the server can accept.
The most common language that we’re using in-house is Python (by the way, it’s an awesome language). The choice of available WSDL libs for python is not great and a lot of libs that exist out there are just outdated. It seems that the only one that is noteworthy is suds.
Suds is a lightweight SOAP python client for consuming Web Services. And its use is really straightforward.
[code language=”python”]
from suds.client import Client
url = ‘https://api-s5.postini.com/dl/api/automatedbatch.wsdl’
client = Client(url)
[/code]
You can easily inspect the service types and methods by parsing client object to string.
[code language=”python”]
print client
Suds ( https://fedorahosted.org/suds/ ) version: 0.4 GA build: R699-20100913
Service ( AutomatedBatchService ) tns="http://postini.com/PSTN/SOAPAPI/v2/automatedbatch"
Prefixes (1)
ns0 = "http://postini.com/PSTN/SOAPAPI/v2/automatedbatch"
Ports (1):
(AutomatedBatchPort)
Methods (22):
addalias(authElem authElem, xs:string userAddressOrId, xs:string aliasAddress, xs:string confirm, )
adddomain(authElem authElem, xs:string orgNameOrId, adddomainargs args, )
.
. # Other functions
.
suspenduser(authElem authElem, xs:string userAddressOrId, xs:string optArgStr1, xs:string optArgStr2, xs:string optArgStr3, )
test(xs:boolean should_work, )
Types (67):
AdminBlockException
AuthenticationException
.
. # Other types
.
testResponse
userRecord
[/code]
As I mentioned before we know exactly how the functions and types are built. Thereby we can use object factory provided by suds. Let’s say we want to execute the `adddomain` method. To do that we need to prepare three objects whose types are `authElem`, xs:string, adddomainargs.
[code language=”python”]
auth = client.factory.create(‘authElem’)
args = client.factory.create(‘adddomainargs’)
[/code]
[code language=”python”]
print auth
(authElem){
apiKey = None
email = None
pword = None
xauth = None
}
print args
(adddomainargs){
domain = None
}
[/code]
As we can see the objects were created for us. In the case of `orgNameOrId` we don’t need to create a special type as it is just a simple string.
Anyway, now we just need to fill the created objects with proper data.
[code language=”python”]
auth.apiKey = ‘< your api key >’
auth.email = ‘info@aeguana.com’
auth.pword = ‘< your password >’
auth.xauth = ‘< your auth key >’
orgNameOrId = ‘www.google.com’
args.domain = ‘www.aeguana.com’
[/code]
And call the method:
[code language=”python”]
resp = adddomain(auth, orgNameOrId, args)
[/code]
But (there is always a ‘but’), sometimes the XML is broken and/or the namespace defined in the XML document is unknown. Therefore we can not create the suds client and we are getting back an error, each time we try to do it. And as it was in my case one of the services was causing this error:
[code language=”python”]
TypeNotFound: Type not found: ‘(Array, http://schemas.xmlsoap.org/soap/encoding/, )’
[/code]
The solution for this is really easy but it’s hard to figure out what’s happening at the beginning.
I found some help by reading the post here on Parky’s Place blog.
To solve the issue we need to tell suds which namespace our XML is using. To find out what namespace it is we need to look at the XML file header.
[code language=”xml”]
<definitions xmlns_wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns_soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns_tns="urn:idu" xmlns_xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/" name="idu" targetNamespace="urn:idu">
# XML body
</definitions>
[/code]
The value from fields “xmlns:tns” and “targetNamespace” are the ones we are interested in. As we can see the namespace used in this document is “urn:idu”. So now we need to instruct the suds client to use this namespace:
[code language=”python”]
tns = "urn:idu"
imp = Import(‘http://schemas.xmlsoap.org/soap/encoding/’, ‘http://schemas.xmlsoap.org/soap/encoding/’)
imp.filter.add(tns)
client = Client(url, plugins=[ImportDoctor(imp)])
[/code]
That’s it, our client is ready to work now!

Leave a Reply

Your email address will not be published. Required fields are marked *