Search code examples
pythonspyne

How to access SOAP headers in Spyne


I can’t get to read even the simplest SOAP header.

I’ve been following the documentation which gives this example:

class RequestHeader(ComplexModel):
    user_name = Mandatory.Unicode
    session_id = Mandatory.Unicode

class UserService(ServiceBase):
    __tns__ = 'spyne.examples.authentication'
    __in_header__ = RequestHeader

    @rpc(_returns=Preferences)
    def some_call(ctx):
        username = ctx.in_header.user_name

But it doesn’t say what the request should look like. I’ve tried:

<soap:Header>
    <user_name>test</user_name>
    <session_id>123</session_id>
</soap:Header>

But ctx.in_header is None. However, ctx.in_header_doc is there, so it tells me it’s the parsing the XML into Python object that fails.

The header I’m trying to parse looks like this:

<soap:Header>
    <credentials>
        <loginToken>
            <token>12345678</token>
            <key>123456789</key>
            <householdId>46345435</householdId>
        </loginToken>
        <deviceId>345345345</deviceId>
        <deviceProvider>aaa</deviceProvider>
  </credentials>
</soap:Header>

How would I go about getting this in ctx.in_header? I tried creating nested objects for each XML element but it doesn’t work. Which doesn’t surprise me since the basic example from the docs doesn’t work either.


Solution

  • You're getting ctx.in_header as None because the incoming document does not fit the object description.

    Your current header could be parsed by something along the lines of:

    class UserService(ServiceBase):
        __in_header__ = Unicode, Integer
    

    ... which does not seem to be what you want.

    Your definition would work for the following input:

    <soap:Header>
      <tns:RequestHeader>
        <tns:user_name>test</user_name>
        <tns:session_id>123</session_id>
      </tns:RequestHeader>
    </soap:Header>
    

    ... where the tns: prefix is defined up there somewhere as the namespace of the RequestHeader object. The namespaces are important -- you need to learn how to work with them if you want your SOAP stuff to work.

    Finally, to parse the credentials tag, you need at least something like a following definition (plus namespace qualifications):

    class LoginToken(ComplexModel):
        _type_info = [
            ('token', Integer),
            ('key', Integer),
            ('householdId', Integer),
        ]
    
    class Credentials(ComplexModel):
        __type_name__ = 'credentials'
        _type_info = [
            ('loginToken', LoginToken),
            ('deviceId', Integer),
            ('deviceProvider', Unicode),
        ]
    

    I hope that helps.