CaramuchoDotCom
CaramuchoDotCom

Reputation: 91

Python - Zeep SOAP Complex Header

I'd like to pass "Complex" Header to a SOAP service using the zeep library.

Here's what it should look like

<soapenv:Header>
    <something:myVar1>FOO</something:myVar1>
    <something:myVar2>JAM</something:myVar2>
</soapenv:Header>

I guess that I succeed in sending a header this way

header = xsd.Element(
    '{http://urlofthews}Header',
        xsd.ComplexType([
        xsd.Element(
        '{http://urlofthews}myVar1',
        xsd.String()),
        xsd.Element(
        '{http://urlofthews}myVar2',
        xsd.String())
        ])
    )

header_value = header(myVar1='FOO',myVar2='JAM')
print (header_value)
   
datasoap=client.service.UserRessourcesCatalog(requete,_soapheaders=[header_value])

But how can I declare and pass the namespace "something" in my Header with the XSD?

As mentionned in the documentation:
http://docs.python-zeep.org/en/master/headers.html

Another option is to pass an lxml Element object. This is generally useful if the wsdl doesn’t define a soap header but the server does expect it

...which is my case, so I tried:

try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET

ET.register_namespace('something', 'http://urlofthews')

headerXML = ET.Element("soapenv:Header")
var1 = ET.SubElement(headerXML, "something:myVar1")
var1.text = "FOO"
var2 = ET.SubElement(headerXML, "something:myVar2")
var2.text = "JAM"


headerDict=xmltodict.parse(ET.tostring(headerXML))
print (json.dumps(headerDict))
       
datasoap=client.service.UserRessourcesCatalog(requete,_soapheaders=headerDict)

But I get:

ComplexType() got an unexpected keyword argument u'soapenv:Header'. Signature: ``

Upvotes: 7

Views: 14541

Answers (4)

Corentin Jacquet
Corentin Jacquet

Reputation: 314

It's an old question, but there are lots of related issues for setting soap headers with zeep. The docs says there is four ways to do it, but does not give example for the last one, so here is one.

It is better than the raw call because you still use zeep for the body and soap itself.

It is simpler than declaring the complete xsd structure.

from zeep import Client
from lxml import etree

headers = etree.XML('<Header><Token xmlns="http://www.example.com/objets/Authentification/1.0">'+result["Token"]+'</Token></Header>')

client = Client("https://www.example.com/services/ServiceName/4.2/Service.svc?singleWsdl")

result = client.service.MethodeName(
        payload,
        _soapheaders=[*headers],
    )

Upvotes: 0

Carlos Martinez
Carlos Martinez

Reputation: 1

From a related question:
Bearer Token authorization header in SOAP client with Zeep and Python

import requests
from zeep import Client, Transport

headers = {
    "Authorization": "Bearer " + get_token()
}
session = requests.Session()
session.headers.update(headers)
transport = Transport(session=session)
client = Client(wsdl=url, transport=transport)

Upvotes: -1

CaramuchoDotCom
CaramuchoDotCom

Reputation: 91

Thx Oblivion02.

I finally use a raw method

headers = {'content-type': 'text/xml'}
body = """<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://blablabla">
<soapenv:Header>
<something:myVar1>FOO</something:myVar1>
<something:myVar2>JAM</something:myVar2>
</soapenv:Header>
<soapenv:Body>
          ...
</soapenv:Body>
</soapenv:Envelope>"""

response = requests.post(wsdl,data=body,headers=headers)

Upvotes: 2

oblivion02
oblivion02

Reputation: 567

I recently encountered this problem, and here is how I solved it.

Say you have a 'Security' header that looks as follows...

<env:Header>
<Security>
    <UsernameToken>
        <Username>__USERNAME__</Username>
        <Password>__PWD__</Password>
    </UsernameToken>
    <ServiceAccessToken>        
        <AccessLicenseNumber>__KEY__</AccessLicenseNumber>
    </ServiceAccessToken>
</Security>
</env:Header>

In order to send this header in the zeep client's request, you would need to do the following:

header = zeep.xsd.Element(
            'Security',
            zeep.xsd.ComplexType([
                zeep.xsd.Element(
                    'UsernameToken',
                    zeep.xsd.ComplexType([
                        zeep.xsd.Element('Username',zeep.xsd.String()),
                        zeep.xsd.Element('Password',zeep.xsd.String()),
                    ])
                ),
                zeep.xsd.Element(
                    'ServiceAccessToken',
                    zeep.xsd.ComplexType([
                        zeep.xsd.Element('AccessLicenseNumber',zeep.xsd.String()),
                    ])
                ),
            ])
        )

header_value = header(UsernameToken={'Username':'test_user','Password':'testing'},UPSServiceAccessToken={'AccessLicenseNumber':'test_pwd'})

client.service.method_name_goes_here(
                    _soapheaders=[header_value],#other method data goes here
                )

Upvotes: 31

Related Questions