How to use zeep to make SOAP requests in python - python

here is my xml:
<?xml version="1.0"?>
<soapenv:Envelope>
<soapenv:Header xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:Security soap:mustUnderstand="1" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>USERNAME</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">1234</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<root xmlns="http://xmlns.oracle.com/Enterprise/tools/schema/InfoRtRequest.v1">
<EMAIL>david</EMAIL>
</root>
</soapenv:Body>
</soapenv:Envelope>
here is my demo:
wsdl = ''
client = Client(
wsdl,
wsse=UsernameToken('USERNAME', '1234'))
response = client.service.get_method(
EMAIL='david')
it raised VadlidationError:
ValidationError: Missing element OPRID (root.OPRID)
I don't know why, please give me some help, thanks.

zeep is advanced library to handle SOAP communications in python. You should provide wsdl file, so that your issue can be better analyzed.
But by looking into the xml request you have provided, it seems the authentication is been done using headers and data is been sent in body. Similar to the usecase i have recently fixed. Refer my xml request of my use case below.
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header>
<ns0:myheaders xmlns:ns0="xxxxxx_stackoverflow_mask_xxxxxx">
<ns0:username>xxxxxx_stackoverflow_mask_xxxxxx</ns0:username>
<ns0:password>xxxxxx_stackoverflow_mask_xxxxxx</ns0:password>
</ns0:myheaders>
</soap-env:Header>
<soap-env:Body>
<ns0:Search02c xmlns:ns0="xxxxxx_stackoverflow_mask_xxxxxx">
<ns0:name>
<ns0:title>Mr</ns0:title>
<ns0:forename>Srikanth</ns0:forename>
<ns0:surname>Badveli</ns0:surname>
</ns0:name>
</ns0:Search02c>
</soap-env:Body>
</soap-env:Envelope>
For the above xml, the code is as follows
from zeep import Client
header_credentials = {'username':'xxxxx','password':'xxxxx'}
tac_data = {'name': {'title':'xxxxx','forename':'xxxxx','surname':'xxxxx'}}
client = Client(wsdl=wsdl)
response = client.service.Search02c(tac_data, _soapheaders={'callcreditheaders':header_credentials})
In the above code, "Search02c" is the operation name for the service. Operation name can be found while inspecting the wsdl file. In my usecase "Search02c" accepts 2 arguments which are body and header."tac_data" is the dictionary of the xml body(not header) and "header_credentials" is the dictionary of the credentials. Your use case might accept single argument clubbing header and body. The arguments structure can be found after operation name in the inspected wsdl file.
You can find the operation name and its structure in the end of the output by running this in your command prompt.
python -mzeep wsdl_file_path.wsdl
The operation for my wsdl file is below.
Operations:
Search02c(searchDefinition: tac_data, _soapheaders={'headers': header_credentials}) -> outputResult: ns1:output
Remember, zeep only accepts dictionary as input data and provides dictionary as output. If you like to receive response as xml, use raw_response=True in the client settings.
For more information, please refer zeep documentation

Related

How to send POST body when creating a python Zeep client

The API I am working with requires that I add a POST body when requesting the wsdl client. I'm using Zeep so it will look like this:
client = Client(wsdl=url, settings=s)
How would I add a post body at this point? I checked the settings documentation and it doesn't include a way for me to that. Is there an alternative way?
If that's not possible by the library, is it possible for me to make the request using the standard python request library and use the Zeep client to process the response?
UPDATE
Here is a sample payload I need to include. Unfortunately, I can't shared the exact URL I using.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:int="http://acme.com/integration/">
<soap:Header>
<int:AcmeNetOptions>
<int:ImposeConcurrencyId>true</int:ImposeConcurrencyId>
<int:UpdateLastModified>true</int:UpdateLastModified>
<int:CanDeleteMissingEntity>true</int:CanDeleteMissingEntity>
<int:LockOnDataRetrieval>Default</int:LockOnDataRetrieval>
</int:AcmeNetOptions>
</soap:Header>
<soap:Body>
<int:Login>
<int:username>username</int:username>
<int:password>password</int:password>
<int:companyname>company</int:companyname>
</int:Login>
</soap:Body>

change XML evelope settings in suds

I'm trying to acces a SOAP API. This works while using SOAP-UI as a test environment.
Now I want to implement it in Suds/Python. The actual request suds makes differs in the soap:Envelope element. I have no idea how to set it so it works.
The correct request made by SOAP-UI
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:plur="pluriform:works:datatypes:DagstatenApp-0">
<soap:Header/>
<soap:Body>
...
</soap:Body>
</soap:Envelope>
with the rather minimal python code:
from suds.client import Client
client = Client(url)
client.set_options(soapheaders=(user, passwd)
result = client.service.getWhatEver(arg1, arg2)
I get this:
<SOAP-ENV:Envelope xmlns:ns0="pluriform:works:datatypes:DagstatenApp-0" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
...
</ns1:Body>
</SOAP-ENV:Envelope>
Which if I copy-paste it in SOAP-UI. I get this error:
<soapenv12:Text xml:lang="EN">Systeemmelding 6EDB::4844 XML Type error (code 19060)
Systeemmelding 6EDB::4844 XML Type error (code 19060)
Error: Systeemmelding XML Type error (6EDB::4844)
XML Type mismatch. Expected tag [http://www.w3.org/2003/05/soap-envelope]Envelope, not [http://schemas.xmlsoap.org/soap/envelope/]Envelope. Error code App:19060
Error: Systeemmelding XML Type error (6EDB::4844)
element start ("SOAP-ENV:Envelope") rejected at 1, 240
Error code App:19060
Generic XML Import IMPL (6EDB::11267)
Generic XML Import (6EDB::9780)</soapenv12:Text>
I tried various examples like: Overwrite the Soap Envelope in Suds python
but they all add another namespace and do not seem to work. Any suggestions would be welcome.

Complex Type issue with SOAPpy

I'm trying to access a function defined in my WSDL from HP Server Automation, I'm able to get servers/etc, but not able to pull anything that takes a server reference specifically via SOAPpy.
import SOAPpy
from SOAPpy import WSDL
from SOAPpy import structType
SOAPpy.Config.debug=1
server = WSDL.Proxy('ServerService.wsdl')
serverRef = structType(name='self', typed=0)
serverRef._addItem('id',SOAPpy.longType(19250001))
print server.getCustAttr(serverRef,key='HPSW_ED_win32_diskspace',useScope=False)
The SOAP envelope generated from this code looks like this:
*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd2="http://www.w3.org/2000/10/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
>
<SOAP-ENV:Body>
<ns1:getCustAttr xmlns:ns1="http://server.opsware.com" SOAP-ENC:root="1">
<xsd:self>
<id xsi:type="xsd2:long">19250001</id>
</xsd:self>
<useScope xsi:type="xsd:boolean">False</useScope>
<key xsi:type="xsd:string">HPSW_ED_win32_diskspace</key>
</ns1:getCustAttr>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And it should look like this ( runs successfully via SOAPUI):
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://server.opsware.com">
<soapenv:Header/>
<soapenv:Body>
<ser:getCustAttr soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<self xsi:type="ser:ServerRef">
<id xsi:type="xsd:long">19250001</id>
</self>
<key xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">HPSW_ED_win32_diskspace</key>
<useScope xsi:type="xsd:boolean">False</useScope>
</ser:getCustAttr>
</soapenv:Body>
</soapenv:Envelope>
I believe the issue is that the xsi:type="ser:ServerRef" is not set, and not really sure how to do that with SOAPpy...
there are two different types of soap styles(RPC literal and Document literal),looks like the mentioned soap server just supports RPC
i saw this problem with soappy and suds. after some tests and benchmarks,i found the problem.
ASP.NET and soappy. you need produce a rpc envelop with python instead document literal envelop style.
just ZSI(The Zolera Soap Infrastructure) works with asp.net and complex types.
this command generates the client proxy for you:
wsdl2py http://terraservice.net/TerraService.asmx?WSDL
and you can import generated modules in your code and use the web methods.

Add Header section to SOAP request using SOAPpy

I need to construct this SOAP query using python SOAPpy module:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<LicenseHeader xmlns="http://schemas.acme.eu/">
<LicenseKey>88888-88888-8888-8888-888888888888</LicenseKey>
</LicenseHeader>
</soap:Header>
<soap:Body>
<GetProductClassification xmlns="http://schemas.acme.eu/">
<GetProductClassificationRequest />
</GetProductClassification>
</soap:Body>
</soap:Envelope>
So I use this code:
from SOAPpy import WSDL
wsdlFile = 'https://example.comt/1.0/service.asmx?wsdl'
server = WSDL.Proxy(wsdlFile)
result = server.GetProductClassification();
The request generated is:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<GetProductClassification SOAP-ENC:root="1">
</GetProductClassification>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
When I send request I get Object reference not set to an instance of an object. I think this might be because I don't have a header section with license key in my request.
How do I modify my code to add header section with LicenseHeader parameter?
I am not sure how to do this in SOAPpy but I do know how to do it in suds. SUDS does the same thing as SOAPpy but it is newer and is still supported. I don't think SOAPpy is supported anymore. Below show's the code to connect to a WSDL and send a soap request:
class MySudsClass():
def sudsFunction(self):
url = "http://10.10.10.10/mywsdl.wsdl"
# connects to WSDL file and stores location in variable 'client'
client = Client(url)
#I have no address set in the wsdl to the camera I connect to so I set it's location here
client.options.location = 'http:/10.10.10.11'
# Create 'xml_value' object to pass as an argument using the 'factory' namespace
xml_value = client.factory.create('some_value_in_your_xml_body')
#This send the SOAP request.
client.service.WSDLFunction(xml_value)
Put this in the script before you send the soap request and it will add any headers you want.
# Namespaces to be added to XML sent
wsa_ns = ('wsa', 'http://schemas.xmlsoap.org/ws/2004/08/addressing')
wsdp_ns = ('http://schemas.xmlsoap.orf/ws/2006/02/devprof')
# Field information for extra XML headers
message = 'mymessage'
address_txt = 'myheader_information'
# Soapheaders to be added to the XML code sent
# addPrefix allow's you to addc a extra namespace. If not needed remove it.
message_header = Element('MessageID', ns=wsa_ns).setText(message)
address_header = Element('Address', ns=wsa_ns).setText(address_txt).addPrefix(p='wsdp', u=wsdp_ns)
header_list = [message_header, address_header]
# Soapheaders being added to suds command
client.set_options(soapheaders=header_list)
This will allow you to add in wsa encding that makes the XML understand:
# Attribute to be added to the headers to make sure camera verifies information as correct
mustAttribute = Attribute('SOAP-ENV:mustUnderstand', 'true')
for x in header_list:
x.append(mustAttribute)
If you use something like this you will be able to add any headers, namespaces etc. I have used this and it worked perfectly.
To add the license header in SUDS add:
license_key = Element('LicenseKey', ns=some_namespace).setText('88888-88888-8888-8888-888888888888')
license_header = Element('LicenseHeader', ns=some_namespace).insert(license_key)
license_attribute = Attribute(xmlns, "http://schemas.acme.eu/")
license_header.append(license_attribute)

How to add header while making soap request using soappy

I have WSDL file, using that i wanted to make soap request which will look exactly like this --
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthSoapHd xmlns="http://foobar.org/">
<strUserName>string</strUserName>
<strPassword>string</strPassword>
</AuthSoapHd>
</soap:Header>
<soap:Body>
<SearchQuotes xmlns="http://foobar.org/">
<searchtxt>string</searchtxt>
</SearchQuotes>
</soap:Body>
</soap:Envelope>
To sovle this, i did this
>> from SOAPpy import WSDL
>> WSDLFILE = '/path/foo.wsdl'
>> server = WSDL.Proxy(WSDLFILE)
>> server.SearchQuotes('rel')
I get this error
faultType: <Fault soap:Server: System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.NullReferenceException: Object reference not set to an instance of an object.
The i debugged it and got this
*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
>
<SOAP-ENV:Body>
<SearchQuotes SOAP-ENC:root="1">
<v1 xsi:type="xsd:string">rel</v1>
</SearchQuotes>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
We can see it doesn't contain any header. I think that WSDL file has some bug.
Now, can anyone suggest me how to add header to this outgoing soap request.
Any sort of help will be appreciated. Thanks in advance
Not tested, but I believe you can use the method the docs suggest to add soap headers, i.e., make and prep a SOAPpy.Header instance, then use server = server._hd (hd) to get a proxy equipped with it (though in your case that does seem to be a workaround attempt to broken WSDL, as you say -- might it be better to fix the WSDL instead?).

Categories