Sending a raw XML request to a SOAP service with Zeep (trying to duplicate an argument)

Question:

I am able to send a simple SOAP request with Zeep.

    with client.settings(strict=False):
        resp = client.service.demandeFicheProduit(
            demandeur=self.xxx, motDePasse=self.yyy,
            ean13s="foo",
            multiple=False)

However, I need to give multiple times the ean13s argument, which is not possible in a Python function call, so I figured I need to build the XML myself.

With Zeep’s debug on, I see that the XML sent is this:

<?xml version='1.0' encoding='utf-8'?>
<soap-env:Envelope >
  <soap-env:Body>
    <ns0:demandeFicheProduit >
      <demandeur>xxx
      </demandeur>
      <motDePasse>yyy
      </motDePasse>
      <ean13s>foo
      </ean13s>
      <multiple>false
      </multiple>
    </ns0:demandeFicheProduit>
  </soap-env:Body>
</soap-env:Envelope>

So I only need to replicate the

      <ean13s>foo
      </ean13s>

part.

Looking into Zeep, I see a Transport.post_xml method: https://github.com/mvantellingen/python-zeep/blob/da8a88b9f5/src/zeep/transports.py#L86 which takes an lxml tree as parameter. (doc)

def post_xml(self, address, envelope, headers):
        """Post the envelope xml element to the given address with the headers.
        This method is intended to be overriden if you want to customize the
        serialization of the xml element. By default the body is formatted
        and encoded as utf-8. See ``zeep.wsdl.utils.etree_to_string``.
        """
        message = etree_to_string(envelope)
        return self.post(address, message, headers)

I tried a post_raw_xml method, without etree_to_string:

    def post_raw_xml(self, address, raw_envelope, headers):
        return self.post(address, raw_envelope, headers)

I call it with the above XML

transport = zeep.Transport()
transport.post_raw_xml("adress", my_xml, {})  # {}: headers?

and the response status is OK (200), however the service answers it is an invalid request.

Are there XML / SOAP intricacies I didn’t pay attention to? Encoding? Headers? (here {})

edit: after spying a bit more the Zeep internals, the headers it sends are

{'SOAPAction': '""', 'Content-Type': 'text/xml; charset=utf-8'}

So I thought I could simply use requests.post, to no avail yet. To use requests, see Sending SOAP request using Python Requests

How to otherwise build an XML manually?

Any more idea on how I can duplicate the eans13 argument?

Thank you.

Asked By: Ehvince

||

Answers:

I solved my problem without Zeep.

I send a raw XML string with requests, I don’t construct an XML manually with lxml or xsd.

What helped me was print-debugging the internals of Zeep’s transport.py/post method (so the headers are {'SOAPAction': '""', 'Content-Type': 'text/xml; charset=utf-8'}
),

this other question: Sending SOAP request using Python Requests to send a post request:

requests.post(url, data=xml, headers=headers)

and being careful on the XML string (yes there is a newline character after the closing <?xml> tag).

The downside is to parse the XML back.

Answered By: Ehvince
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.