Making a SOAP request using Python requests module - python

I used python requests module for REST requests.
I am trying to make a soap request but I wondered couldn’t get an example for this .
Here is My soap body and headers.
<auth>
<apikey>xcvzxcvcxzv-a0-0035c6fbc04f</apikey>
</auth>
body
<reports>
<report>
<name>Test</name>
</report>
</reports>
And here is wsdl url
https://ltn.net/webservices/booking/r1/index.wsdl
Please tell me how can I make a post request here using python. If it is not possible using requests module then what could be the other alternatives?

I ran into the same problem recently, and unfortunately neither suds nor jurko-suds(a maintained fork of suds) were able to help.
This is mainly because suds kept generating wrongly formatted soap envelope (this especially happens if the soap that is supposed to be generated has some content that's supposed to be inside a CDATA) different from what the server was expecting. This was the case even when I tried injecting the soap envelope myself using the __inject option.
Here's how I solved it using python requests
import requests
request = u"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:req="http://SOME_URL">
<soapenv:Header>
<user>{0}</user>
<pass>{1}</pass>
</soapenv:Header>
<soapenv:Body>
<req:RequestInfo><![CDATA[<?xml version='1.0' encoding='UTF-8'?><request xmlns='http://SOME_OTHER_URL'>
<Call>
<callID>{2}</callID>
...
</Call>
<Foo>
<Bar>
<Baz>{3}</Baz>
...
</Bar>
<Neytri>
...
</Neytri>
</Foo>
<Title>{4}</Title>
</request>]]></req:RequestInfo>
</soapenv:Body>
</soapenv:Envelope>""".format('Jake_Sully',
'super_secret_pandora_password',
'TYSGW-Wwhw',
'something_cool',
'SalaryPayment',
'Pandora_title',
)
encoded_request = request.encode('utf-8')
headers = {"Host": "http://SOME_URL",
"Content-Type": "application/soap+xml; charset=UTF-8",
"Content-Length": str(len(encoded_request)),
"SOAPAction": "http://SOME_OTHER_URL"}
response = requests.post(url="http://SOME_OTHER_URL",
headers = headers,
data = encoded_request,
verify=False)
print response.content #print response.text
What was really important was to specify the Content-Type in the headers and also the SOAPAction.
According to the SOAP 1.1 specifiaction
The SOAPAction HTTP request header field can be used to indicate the intent of the SOAP HTTP request. The value is a URI identifying the intent. SOAP places no restrictions on the format or specificity of the URI or that it is resolvable. An HTTP client MUST use this header field when issuing a SOAP HTTP Request.
The value of SOAPAction can usually be found in the wsdl file of the API call that you want to make; if absent from the wsdl file then you can use an empty string as the value of that header
Also see:
http://archive.oreilly.com/pub/post/unraveling_the_mystery_of_soap.html
http://www.prodigyproductionsllc.com/articles/programming/call-a-webservice-using-soap-and-python/

To work with a SOAP server you should use a specialized library. Unfortunately, there is no good SOAP client modules for Python, the best one I've used is suds.

This is largely hypothetical since I'm not aware of anyone actually having implemented it but suds supports making custom implementations of suds.transport.Transport. Once such is suds.transport.http.HttpTransport. So technically by implementing a transport subclass you could create a suds transport that uses requests.
http://jortel.fedorapeople.org/suds/doc/suds.transport.http.HttpTransport-class.html is what's used by default and it returns
http://jortel.fedorapeople.org/suds/doc/suds.transport.Reply-class.html so as you can see, it should be fairly simple to wrap requests replies so that suds understands them. Transport request (that should be sent with requests) is documented here
http://jortel.fedorapeople.org/suds/doc/suds.transport.Request-class.html
I might sooner or later implement this if no one beets me to it
Why all this effort? Because suds uses urllib2 internally which is far inferior to python-requests as a HTTP client implementation.
Yet one more edit: I made a gist available as a starting point https://gist.github.com/nanonyme/6268358 . It's MIT code and untested but should work as a starting point for the transport.

In case anyone ends up reading this: suds-based solutions are mostly stagnated but there's a newer library called zeep written on top of requests and lxml. It is a completely separate solution and not a suds fork like these others. I know from personal experience that this is in use in some enterprise environments.

Related

Zeep vs Requests for SOAP APIs in Python

So I know that Python's requests module can be used to handle REST APIs, and as per this answer here, requests can also handle SOAP APIs as well.
I've worked only with REST APIs so far, but of the few people I know who work with SOAP APIs, they almost always use another module zeep.
Is there anything I'm missing?
Why is there a need for a whole seperate module, when it is possible using requests as well - and more importantly, why doesn't anybody just uses requests instead of using zeep?
Ease of use and reusability. While you could use the requests module and write raw XML, Zeep is a high level interface which generates the XML automatically

python 3.x SOAP library for writing serverless webservice on AWS

I need to convert some legacy Java code that implements a SOAP server - I need to convert it from java to python 3.x and I need to deploy the SOAP webservices on AWS Lambda. There is plenty of documentation on how to create REST web services on AWS Lambda in python, but I'm finding it really hard to find any information on writing a SOAP service. There are some client libraries for python SOAP, but I can't seem to find any server-side libraries or examples of how one would do this on AWS Lambda. I found zeep, which is meant to be a client library, and pysimplesoap, but in neither case is it clear how to use these on AWS Lambda. Any suggestions?
UPDATE: So I discovered that SOAP over HTTP is simply a call to HTTP POST which passes the SOAP request message as the HTTP body. (Of course there are headers in the HTTP request too that indicate that the body is a soap/xml message). So, to deploy to AWS Lambda, I basically need to deploy an HTTP PSOT webservice, which is easy enough using Zappa and Flask (or Django). The only tricky part is inside the post() function. Inside that function I would have to:
Get the request.body (SOAP/XML)
Use some python library to extract the items of interest from the SOAP message, perhaps parsing the entire message using a python XML parser
Execute the business logic code that creates a result, say a dictionary
Use some python library to convert that result dictionary to a SOAP response and let AWS Lambda send that SOAP response back
It is parts 2 and 4 that I am not quite sure how to do. I can use xml.etree.ElementTree to parse the XML, but I suspect there might be a better/faster/simpler way. For the output, is there a way I can use something like zeep to take a dictionary of inputs and create a SOAP response message? The zeep library is meant to read the WSDL document and create request SOAP messages, not response SOAP messages, so I'm not exactly sure how to create a SOAP response message using zeep. Has anyone else done this or know of a better way to do it?

Python 2.7 urllib2 raising urllib2.HTTPError 301 when hitting redirect with xml content

I'm using urllib2 to request a particular S3 bucket at hxxp://s3.amazonaws.com/mybucket. Amazon sends back an HTTP code of 301 along with some XML data (the redirect being to hxxp://mybucket.s3.amazonaws.com/). Instead of following the redirect, python raises urllib2.HTTPError: HTTP Error 301: Moved Permanently.
According to the official Python docs at HOWTO Fetch Internet Resources Using urllib2, "the default handlers handle redirects (codes in the 300 range)".
Is python handling this incorrectly (presumably because of the unexpected XML in the response), or am I doing something wrong? I've watched in Wireshark and the response comes back exactly the same to python's request as it does to me using a web client. In debugging, I don't see the XML being captured anywhere in the response object.
Thanks for any guidance.
Edit: Sorry for not posting the code initially. It's nothing special, literally just this -
import urllib2, httplib
request = urllib2.Request(site)
response = urllib2.urlopen(request)
You are better off using the requests library. requests handle redirection by default : http://docs.python-requests.org/en/latest/user/quickstart/#redirection-and-history
import requests
response = requests.get(site)
print(response.content)
I don't get the problem with urllib2, I tried to look into the documentation https://docs.python.org/2/library/urllib2.html but it doesn't look intuitive.
It seems that in Python3, they refactored it to make it less a burden to use, but I am still convinced that requests is the way to go.
Note The urllib2 module has been split across several modules in
Python 3 named urllib.request and urllib.error. The 2to3 tool will
automatically adapt imports when converting your sources to Python 3.

Request XML from SUDS python

Is there any method to return the SOAP Request XML before triggering a call to SOAP method in Suds library?
The client.last_sent() returns request XML after triggered the call. But I want to see before triggering the call.
Yes this is possible and seems to be used in different "fixer" implementations to take care of buggy servers. Basically you should write a MessagePlugin and implement the sending method.

python microframeworks and the requests library

Working on a side project in python that both initiates http requests and has a small web server. It got me thinking - it seems like every python microframework has its own model for accessing properties of the http request (e.g. the underlying request object that you can use to get at the querystring parameters, headers, etc. and the underlying response object for setting the status code, response headers, etc). They all allow you access to the same data and they've all kind of re-invented the wheel.
Are there any microframeworks that use the Request and Response objects from the popular requests library instead of having their own implementation? It seems like the requests library is becoming the canonical way to do http requests in python, so this would make a framework especially minimal. It would also be cool when making apps that essentially glue other services together because forwarding/wrapping requests would be trivial. You could just change the .url attribute on the incoming request and call .prepare() to forward the request (yes, for simple forwarding doing it at the webserver level makes more sense, but you get the idea).
Or if there aren't any frameworks that do this in particular, are there any with similar benefits i.e. the incoming http request object also works as an http client?
Edit: Wanted to point out that this is how the http Request object works in Go, that's partly what inspired my question. From the net/http library "A Request represents an HTTP request received by a server or to be sent by a client."
Flask is based on Werkzeug. Werkzeug itself is using Request which itself is using BaseRequest. But this is not the Requests library.
Note that there was a plan to create an httpcore library using both Requests and Werkzeug, but that seems to have stopped. That said both projects are kicking.
Some people have modified Flask in their apps using Requests

Categories