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.
Related
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
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?
I was looking at the Google BigQuery API reference sample Python code, and I came across the execute() call.
Can anyone provide me with documentation on what this call does?
You linked to code of the form:
bigquery.jobs().insert(...).execute();
The .jobs() call gets an object represent the BigQuery jobs collection.
The .insert(...) call creates a request object representing a (future) call to the BigQuery jobs.insert API method with the specified parameters. But note that this code only constructs the request--it does not actually send the request.
The .execute() call actually sends the API request to the BigQuery API and returns the response.
Note that this is an automatically-generated Java client library for the BigQuery API. The structure of these API clients is similar for all Google APIs.
This page hints at what execute might do in certain scenarios...
https://cloud.google.com/bigquery/querying-data
But it really should be obvious... It executes your query. Probably though a http protocol of some sort.
If you have all of the API in front of you, you should be able to find where execute is defined on certain classes.
execute() is an inherited property of many types of requests from what it seems.
I am using the requests module to make HTTP calls internally within my module.
I understand that this:
r = requests.post('http://github.com', allow_redirects=True)
will follow HTTP redirects.
Of course, I make multiple calls to requests from my own modules API and I want to write a unit test that ensures that requests is always following redirects. How should I go about this?
On first blush, my thought is to fire off a simple HTTP server in my tests to mimic the HTTP calls. I'm not sure how I can mock out the whole requests method calls which rely on network communications.
If it's a requirement that your code always follow redirects, then I would encode this explicitly in an interface function. Then insist that all calls to requests.post are made via your function instead. In its simplest form, this is just a wrapper method:
def my_post(*args, **kwargs):
return requests.post(*args, allow_redirects=True, **kwargs)
If you wanted to preserve the existing API, and just override its behaviour, you could monkeypatch and decorate the third-party function at runtime.
You should avoid testing that the library itself performs the redirects. That should be tested elsewhere, and presumably you trust the library. All you need to test is that you call the library function correctly. This is a general principle.
That keeps your test simple: just mock the call to requests.post, and confirm the arguments you intend, including allow_redirects=True, are passed.
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.