Reputation: 359
The WSDL file for a ServiceNow SOAP API has the request_payload defined as a string when it's actually a dictionary. As a result any time I query the service, I get error:
"ValueError: The String type doesn't accept collections as value".
Section of WSDL file:
<wsdl:definitions targetNamespace="http://www.service-now.com/ChangeOperation" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://www.service-now.com/ChangeOperation" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<wsdl:types>
<xsd:schema elementFormDefault="qualified" targetNamespace="http://www.service-now.com/ChangeOperation">
<xsd:element name="changeOperationRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="0" name="source_system" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="source_uid" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="request_type" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="request_payload" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
A successful SOAP request using SOAPUI:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns0="http://www.service-now.com/ChangeOperation">
<soapenv:Header/>
<soapenv:Body>
<ns0:changeOperationRequest>
<!--Optional:-->
<ns0:source_system>Script</ns0:source_system>
<!--Optional:-->
<ns0:source_uid>131318</ns0:source_uid>
<!--Optional:-->
<ns0:request_type>getChangeRequests</ns0:request_type>
<!--Optional:-->
<ns0:request_payload>
<start_date>2020-01-08T00:00:00</start_date>
<status_list>Proposed</status_list>
<owning_stream>IB IT</owning_stream>
<full_details>no</full_details>
<result_limit>100</result_limit>
</ns0:request_payload>
</ns0:changeOperationRequest>
</soapenv:Body>
</soapenv:Envelope>
Is it possible to override the data type read in from the WSDL file, or alternatively is there any other way to force Zeep to send the field as a string?
I've tried unpacking the dictionary:
xml = client.service.changeOperationRequest(**request_dict)
and setting keyword arguments and only request_payload as a dictionary, but it results in the same error:
xml = client.create_message(client.service, 'changeOperationRequest', source_system='Script',source_uid='131318',request_type='getChangeRequests',request_payload=dictionary)
Even simply setting request_payload to the resulting xml doesn't work as the xml tags get expanded. Although I would rather not have to go down the route of manually creating the xml, that seems to somewhat defeat the point of using Zeep.
xml = client.create_message(client.service, 'changeOperationRequest', source_system='EQ CAB Report Script',source_uid='131318',request_type='getChangeRequests',request_payload='<start_date>2020-01-07T00:00:00</start_date><status_list>Proposed</status_list><owning_stream>IB IT</owning_stream><full_details>no</full_details><result_limit>100</result_limit>')
XML output:
<sn0:request_payload><start_date>2020-01-07T00:00:00</start_date><status_list>Proposed</status_list><owning_stream>IB IT</owning_stream><full_details>no</full_details><result_limit>100</result_limit></ubs:request_payload>
Upvotes: 0
Views: 1396
Reputation: 359
I have gone down the route of sending the dictionary as a string type instead. In order to not expand the escape the xml tags, I used the Zeep plugin helper.
Taken from: python zeep: send un-escaped xml as content
from zeep import Client, xsd, Plugin
class my_plugin(Plugin):
def egress(self, envelope, http_headers, operation, binding_options):
xmlString = ET.tostring(envelope, encoding='unicode')
xmlString = xmlString.replace("<", "<")
xmlString = xmlString.replace(">", ">")
newenvelope = ET.XML(xmlString)
return newenvelope, http_headers
# create the client:
client = Client(wsdl_url, transport=transport, plugins=[my_plugin()])
# call service as you would normally
client.service.changeOperationRequest()
Upvotes: 0