Henrik Heimbuerger
Henrik Heimbuerger

Reputation: 10183

How do I raise a SOAP Fault with a structured detail element in Spyne?

The Spyne manual points out that the right way to create SOAP Faults with Spyne is to raise instances of spyne.model.fault.Fault (or your own subclass):

@add_metaclass(ComplexModelMeta)
class Fault(ComplexModelBase, Exception):
    # ...

I'm trying to understand why it subclasses ComplexModelBase. My initial assumption was that I declare the elements I want to go into the SOAP Fault's <detail> element in my Fault subclass, like so:

class MyApplicationError(Fault):
    __namespace__ = 'http://myapplication.com/ns'
    _type_info = [
        ('reason', Unicode),
    ]

However, when actually raising this exception, it looks like I have to pass a plain dict into the detail parameter of the constructor.

What is the best practice for filling the detail with a structured set of data? Do I even declare this structure in my Fault subclass?
If yes, how do I fill it? If not, why does Fault subclass ComplexModelBase?

Upvotes: 2

Views: 1264

Answers (1)

Burak Arslan
Burak Arslan

Reputation: 8001

Fault(detail={'foo': {'bar': 123}})

will serialize to:

<ns0:Fault xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">
  <faultcode>soap11env:Server</faultcode>
  <faultstring>Fault</faultstring>
  <faultactor></faultactor>
  <detail>
    <foo>
      <bar>123</bar>
    </foo>
  </detail>
</ns0:Fault>

You can write a new constructor for Fault in a subclass to make it easier to generate the details dict. E.g.:

class SuperFault(Fault):
    def __init__(self, foo, bar):
        super(SuperFault, self).__init__('Server.SuperFault', 'E001234',
                                detail={'SuperFault': {'foo': foo, 'bar': bar}})

Please note that due to some stupid limitation, the length of the dict passed to detail must be 1. Please file an issue if that's a problem for you.

Upvotes: 2

Related Questions