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)
Related
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
I'm interfacing with a SOAP API, wherein a particular method requires a raw XML string as a parameter. Like so:
import suds.client as sudscl
client = sudscl.Client('http://host/ws.wsdl', location='http://host/ws')
session = 'test123'
options = '<rawXML><Item>Foobar</Item></rawXML>'
result = client.service.ExecuteSearch(session, options)
Pretty straight-forward. However, suds HTML-encodes the XML string I just sent in, like this:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://host/ws">
<SOAP-ENV:Header/>
<ns1:Body>
<ns0:ExecuteSearch>
<ns0:session>test123</ns0:session>
<ns0:options>
<rawXML&rt;<Item&rt;Foobar</Item&rt;</rawXML&rt;
</ns0:options>
</ns0:ExecuteSearch>
</ns1:Body>
</SOAP-ENV:Envelope>
Boo! Is there any way to get suds to pass in the XML string un-altered?
Thanks!
Ok, got it.
from suds.sax.text import Raw
import suds.client as sudscl
client = sudscl.Client('http://host/ws.wsdl', location='http://host/ws')
session = 'test123'
options = Raw('<rawXML><Item>Foobar</Item></rawXML>')
result = client.service.ExecuteSearch(session, options)
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.
I am having a problem with python suds trying to create a proper Suds XML Request:
This is my suds Code (after a few trials):
from suds import *
from suds.client import Client
from suds.transport.http import HttpAuthenticated
import logging
url = 'http://ws/webservices/600/ws.asmx?wsdl'
soap_client = Client(url, location='http://ws/webservices/600/ws.asmx')
soap_client.set_options(port='GatewayWebServiceSoap')
person = soap_client.factory.create('checkIfExists')
person.UserID = 'toni.tester#anywhere.at'
person.SessionID = ''
eventService = soap_client.service.CustomerService(person)
print 'last received:'
print soap_client.last_received()
print '-------------------------------------'
print 'last sent:'
print soap_client.last_sent()
This is what my suds sends:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://service.example.at/gateway/v6.00" 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>
<ns0:Service>
<ns0:Service>
<ns0:SessionID></ns0:SessionID>
<ns0:UserID>toni.tester#anywhere.at</ns0:UserID>
</ns0:Service>
</ns0:Service>
</ns1:Body>
</SOAP-ENV:Envelope>
And this is what the WebService expects:
<?xml version="1.0" encoding="UTF-8"?>
<GATEWAY xmlns="urn:service-example-at:gateway:v4-00">
<Service>
<checkIfExists>
<SessionID></SessionID>
<UserID>test</UserID>
</checkIfExists>
</Service>
</GATEWAY>
My Questions:
How can I change SOAP-ENV:Envelope -> GATEWAY
How can I remove the namespaces ns1, ns0?
How can I remove the Body
If you really don't care about WSDL and stuff you can easily write request generator yourself since xml request is just a string template. That's what i did for my soapy needs.
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?).