Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating the xml format to pass to zeep

Tags:

python

xml

zeep

I'm new to zeep. I have the following that works very well:

import zeep

from zeep.cache import SqliteCache

from zeep.transports import Transport
wsdl = 'https://emaapitest.eset.com/Services/v2015_1/MSPService.svc?singleWsdl'
transport = Transport(cache=SqliteCache())
client = zeep.Client(wsdl=wsdl, transport=transport )

With the above I can use the defined API for most calls. For example:

data = {'Username': 'xxxx123',  'Password': 'Secretpassword'}
loginreq = client.service.Login(data)

data = {'LoginID': 'xxxyyy', 'Token': 'gregrwevds543',  'CompanyID': 123}
company_details = client.service.GetCompanyDetails(data)

That all works well. However the API call to UpdateSite needs a different format as below:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:msp="http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.Requests">
       <soapenv:Header/>
       <soapenv:Body>
          <tem:UpdateSite>
         <tem:request>
            <msp:LoginID>123abc</msp:LoginID>
            <msp:Token>hpjzncpduqyfreyakcsdilqv</msp:Token>
                  <msp:LicenseRequests>
                       <LicenseRequest xmlns:d7="http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.Requests"
                    i:type="d7:LicenseCreateRequest" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.ViewModels">
                           <d7:ProductCode>112</d7:ProductCode>
                           <d7:Quantity>3</d7:Quantity>
                           <d7:Trial>false</d7:Trial>
                       </LicenseRequest>
                 </msp:LicenseRequests>
            <msp:SiteID>123456</msp:SiteID>
         </tem:request>
          </tem:UpdateSite>
       </soapenv:Body>
    </soapenv:Envelope>

That is I need to change the namespace on the LicenseRequest. Is there any way I can generate this xml (say using etree maybe) and then pass this into zeep? Exact syntax would be a great help. Thanks for any help in advance.

like image 803
Kevin Sheahan Avatar asked Feb 05 '18 11:02

Kevin Sheahan


1 Answers

Here's an example to format the SOAP Web Services XML message per the WSDL:

In this example, I found the namespace prefixes assigned by Zeep in client.wsdl.dump(); see example of this near the bottom of the answer.

>>> import zeep
>>> client = zeep.Client('https://emaapitest.eset.com/Services/v2015_1/MSPService.svc?singleWsdl')
>>> # note - the namespace ns2 was assigned by zeep - see client.wsdl.dump() tip later in this answer
>>> license_create_type = client.get_type('ns2:LicenseCreateRequest')
>>> # Creating an empty object reminds me of the property names, so I don't have to guess
>>> license_create_type()
{
    'Note': None,
    'ProductCode': None,
    'Quantity': None,
    'ServerName': None,
    'Trial': None
}
>>> my_create = license_create_type(ProductCode=112,Quantity=3,Trial=False)
>>> my_create
{
    'Note': None,
    'ProductCode': 112,
    'Quantity': 3,
    'ServerName': None,
    'Trial': False
}
>>> my_type = client.get_type('ns2:SiteUpdateRequest')
>>> # Reference for specifying arrays in Zeep: https://github.com/mvantellingen/python-zeep/issues/145#issuecomment-321614947
>>> req = my_type(LoginID="123",Token="mytoken",LicenseRequests={'LicenseRequest':[my_create]})
>>> # To call the service:   (assuming valid credentials?)
>>> # client.service.UpdateSite(req)

Here's the Python view of the web service request:

>>> req
{
    'LoginID': '123',
    'Token': 'mytoken',
    'Active': None,
    'LicenseRequests': {
        'LicenseRequest': [
            {
                'Note': None,
                'ProductCode': 112,
                'Quantity': 3,
                'ServerName': None,
                'Trial': False
            }
        ]
    },
    'Name': None,
    'SecurityAdminRequests': None,
    'SiteID': None,
    'SupportLegacyKey': None
}

Here's the XML view of the web service request:

>>> # Debugging output to see raw XML...
>>> node = client.create_message(client.service, 'UpdateSite', req)
>>> from lxml import etree
>>> xml_str = etree.tostring(node, pretty_print=True).decode()
>>> print(xml_str)
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
  <soap-env:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
    <wsa:Action>http://tempuri.org/IMSPService/UpdateSite</wsa:Action>
    <wsa:MessageID>urn:uuid:c3d7d838-6ce8-477b-ad7d-23e99e800a80</wsa:MessageID>
    <wsa:To>https://emaapitest.eset.com/Services/v2015_1/MSPService.svc</wsa:To>
  </soap-env:Header>
  <soap-env:Body>
    <ns0:UpdateSite xmlns:ns0="http://tempuri.org/">
      <ns0:request>
        <ns1:LoginID xmlns:ns1="http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.Requests">123</ns1:LoginID>
        <ns2:Token xmlns:ns2="http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.Requests">mytoken</ns2:Token>
        <ns3:LicenseRequests xmlns:ns3="http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.Requests">
          <ns4:LicenseRequest xmlns:ns4="http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.ViewModels" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns3:LicenseCreateRequest">
            <ns3:ProductCode>112</ns3:ProductCode>
            <ns3:Quantity>3</ns3:Quantity>
            <ns3:Trial>false</ns3:Trial>
          </ns4:LicenseRequest>
        </ns3:LicenseRequests>
      </ns0:request>
    </ns0:UpdateSite>
  </soap-env:Body>
</soap-env:Envelope>

Tip: use client.wsdl.dump()

I usually start a project by reading client.wsdl.dump() to see the mappings generated by Zeep, starting from the "Bindings" and "Operations" at the bottom, then working backwards through the types. This is usually all you need to get started.

>>> import zeep
>>> client = zeep.Client('https://emaapitest.eset.com/Services/v2015_1/MSPService.svc?singleWsdl')
>>> client.wsdl.dump()

Prefixes:
     myprefix: http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.Requests
     xsd: http://www.w3.org/2001/XMLSchema
     ns0: http://tempuri.org/
     ns1: http://schemas.microsoft.com/2003/10/Serialization/
     ns3: http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.Responses
     ns4: http://schemas.microsoft.com/2003/10/Serialization/Arrays
     ns5: http://schemas.datacontract.org/2004/07/MSPApi.Services.v2015_1.ViewModels

Global elements:
<SNIP - VERY LONG OUTPUT>

Global types:
<SNIP - VERY LONG OUTPUT>
     ns2:SiteUpdateRequest(LoginID: xsd:string, Token: xsd:string, Active: xsd:boolean, LicenseRequests: ns5:ArrayOfLicenseRequest, Name: xsd:string, SecurityAdminRequests: ns2:ArrayOfSecurityAdminRequest, SiteID: xsd:long, SupportLegacyKey: xsd:boolean)

<SNIP - VERY LONG OUTPUT>
Service: MSPService
     Port: BasicHttpBinding_IMSPService (Soap11Binding: {http://tempuri.org/}BasicHttpBinding_IMSPService)
         Operations:
<SNIP - VERY LONG OUTPUT>
            UpdateSite(request: ns2:SiteUpdateRequest) -> UpdateSiteResult: ns3:SiteDetailsResponse
<SNIP - VERY LONG OUTPUT>
>>>
like image 124
Chuck T. Avatar answered Sep 18 '22 17:09

Chuck T.