2

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?

Henrik Heimbuerger
  • 9,924
  • 6
  • 56
  • 69

1 Answers1

2
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.

Burak Arslan
  • 7,671
  • 2
  • 15
  • 24
  • Thanks for the tip, that's basically as far as I got. But can I not generate my detail element from the `__type_info__` of a `ComplexModel`, similarly to how I generate a SOAP response from my own `ComplexModel` subclasses? – Henrik Heimbuerger Mar 01 '15 at 20:16
  • There's two major issues with this solution: a) Using the dictionary method you outlined, I don't need to declare the Fault subclass anymore (or declare it as `_throws` on the `@rpc` decorator). Then, I'm missing the Fault in the `` on the binding and the `` on the portType. b) On the other hand, if I do declare it, and use this as the exception to raise with the `detail` argument on the constructor, Spyne will write the fields in the Fault twice, once in the `` element, and once outside next to it. – Henrik Heimbuerger Mar 21 '15 at 11:40
  • Additionally, Spyne always prefixes the content of the `` element with `senv:`, even thought that namespace is not declared. I generally don't see anything in the [spec on SOAP Fault Codes](http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383510) that would imply that they ever need to be namespace-prefixed. – Henrik Heimbuerger Mar 21 '15 at 18:48