get the full path of web service's methods from wsdl file - python

I am working with suds library -python 2.7- and I would like to get the full path of all methods from a wsdl file.
I used this code to get the list of methods from a wsdl file :
from suds.client import Client
url = "http://www.webservicex.net/country.asmx?WSDL"
client = Client(url)
list_of_methods = [method for method in client.wsdl.services[0].ports[0].methods]
and I get something like this :
[GetCurrencyCodeByCurrencyName, GetCurrencyByCountry, GetCurrencyCode, GetCountries, GetCurrencies, GetISOCountryCodeByCountyName, GetISD, GetCountryByCurrencyCode, GetGMTbyCountry, GetCountryByCountryCode]
But I want to get something like this :
[http://www.webserviceX.NET/GetCountryByCountryCode, ...]
so, how can I do this ?

What about using a qname attribute of a port?
from suds.client import Client
url = "http://www.webservicex.net/country.asmx?WSDL"
client = Client(url)
port = client.wsdl.services[0].ports[0]
list_of_methods = [port.qname[1] + '/' + method for method in port.methods]
print(list_of_methods)

Related

Python and socket - connet to specific path

I need to connect/send msg to http://localhost:8001/path/to/my/service, but I am not able to find how to do that. I know how to send if I only have localhost and 8001, but I need this specific path /path/to/my/service. There is where my service is running.
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(<full-url-to-my-service>)
s.sendall(bytes('Message', 'utf-8'))
Update
My service is running on localhost:8001/api/v1/namespaces/my_namespace/services/my_service:http/proxy. How can I connect to it with python?
As #furas told in the comments
socket is primitive object and it doesn't have specialized method for this - and you have to on your own create message with correct data. You have to learn HTTP protocol and use it to send
This is a sample snippet to send a GET request in python using requests library
import requests
URL = 'http://localhost:8001/path/to/my/service'
response_text = requests.get(URL).text
print(response_text)
This assumes the Content-Type that GET URL produces is text. If it is json, then a minor change is required
import requests
URL = 'http://localhost:8001/path/to/my/service'
response_json = requests.get(URL).json()
print(response_json)
There are other ways to achieve the same using other good frameworks like urllib, and so on.
Here is the documentation of requests library for reference
sendall() requires bytes, so String must be encoded.
s.sendall("foobar".encode())

Unable to consume a .NET WCF service in Python

I am trying to access a .NET WCF web service from Python and am getting the following error - would anyone be able to let me know what I am doing wrong:
File "C:\temp\anaconda3\lib\site-packages\suds\mx\literal.py", line 87, in start
raise TypeNotFound(content.tag)
suds.TypeNotFound: Type not found: 'authToken'
Below is the python code that I have:
import uuid
from suds.client import Client
from suds.xsd.doctor import Import, ImportDoctor
url = 'http://something/something?wsdl'
imp = Import('http://www.w3.org/2001/XMLSchema', location='http://www.w3.org/2001/XMLSchema.xsd')
imp = Import('http://schemas.xmlsoap.org/soap/encoding/')
imp = Import('http://schemas.xmlsoap.org/soap/encoding/')
imp.filter.add('http://tempuri.org/')
doctor = ImportDoctor(imp)
client = Client(url, doctor=doctor, headers={'Content-Type': 'application/soap+xml'})
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.client').setLevel(logging.DEBUG)
logging.getLogger('suds.transport').setLevel(logging.DEBUG)
logging.getLogger('suds.xsd.schema').setLevel(logging.DEBUG)
logging.getLogger('suds.wsdl').setLevel(logging.DEBUG)
client.set_options
myMethod = client.factory.create('myMethod')
myMethod.authToken = uuid.UUID('xxxxxxxx-35f4-4b7b-accf-yyyyyyyyyyyy')
print(f'CLIENT: {client}')
print(f'myMethod: {myMethod}')
ls_Token = client.service.myMethod(myMethod)
print(f'ACCESSTOKEN: {ls_Token}')
Create ResponseData object, the type is defined in wsdl, if there are multiple schemas, you need to add a prefix, such as ns0, ns1, etc.
ResponseData = client.factory.create('ns1:ResponseData')
ResponseData.token = "Test"
Make sure that the properties of the object you created exist,You can view the properties of the object after successfully creating the object.
ResponseData = client.factory.create('ns1:ResponseData')
ResponseData.token = "Test"
print ResponseData
The following picture is the property of ResponseData object:
If I use the following code I will get the same error as you:
ResponseData = client.factory.create('ns1:ResponseData')
ResponseData.authToken = "Test"
So you need to check whether the myMethod object has authToken property.
We could not get it to work with SOAP WCF and had to modify it to a REST based service to make it work. Python seems to work better with REST service.

WebService request with python suds by XML

i'm trying to comunicate with a webserver with python. I'm using the suds library. Actually i'm pretty new with this.
Usually, to comunicate with this WebServer a send a xml message and i get a response. So this is what i would like to do with python.
Here's the code i wrote:
from suds.client import Client
with open("PATH","r") as f:
file=f.read()
url='URL'
client = Client(url)
httpHeaders = {'Content-Type': 'text/xml', 'SOAPAction': 'ACTION'}
client.set_options(headers=httpHeaders)
Now i don't know how to make the request. I tried this:
print client.service.test(__inject={'msg': file})
But i got the error:
Exception: No services defined
The problem seems clear, but i don't know haw to procede. Any suggestion ?

Extracting Cookie from SOAP Response in SUDS

I have to work with an API that has multiple services. All of which require the JSESSION cookie from the authentication one below. When I call the next service however, it doesn't keep the cookie and so rejects them.
from suds.client import Client
url = 'http://example/ws/Authenticate?wsdl'
client = Client(url)
result = client.service.connect(username='admin', password='admin')
print client.options.transport.cookiejar
>>> <cookielib.CookieJar[<Cookie JSESSIONID=XXXXXXXXXX for localhost.local/Service/>]>
I believe that the way to get it to keep this cookie is to extract it, then provide it as a custom header in the format: -
url = 'http://example/ws/dostuffnowloggedin?wsdl'
client2 = Client(url, headers= { 'Cookie': 'JSESSIONID=value'})
But I can't figure out how to do it. I've reviewed the SUDS Docs, URL2LIB and Cookiejar python docs, looked over stack & asked on Reddit. This is the first question I've asked on Stack, I've tried to make it meaningful and specific, but if I've commited a faux par, tell me and I'll do my best to correct it.
Try this.
from suds.client import Client
url = 'http://example/ws/Authenticate?wsdl'
client = Client(url)
result = client.service.connect(username='admin', password='admin')
url2='url of second service'
client2=Client(url2)
client2.options.transport.cookiejar=client.options.transport.cookiejar

How to make a SOAP request by using SOAPpy?

I'm trying to call a method using a SOAP request by using SOAPpy on Python 2.7. The method is called GetCursOnDate and returns exchange rates. It takes a date parameter.
I'm using the following code:
from SOAPpy import SOAPProxy
import datetime
date=datetime.datetime.now()
namespace ="http://web.cbr.ru/"
url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx"
server = SOAPProxy(url,namespace)
print (date)
server.GetCursOnDate(date)
But I get back an error:
Fault soap:Client: Server did not recognize the value of HTTP Header SOAPAction: GetCursOnDate.
Why do I get this error?
By default, SOAPpy uses the method name as the value of the HTTP SOAPAction header. If you run the following code you will see the value in the debug output:
from SOAPpy import SOAPProxy
from datetime import datetime
input = datetime.now()
namespace = "http://web.cbr.ru/"
url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx"
proxy = SOAPProxy(url, namespace)
proxy.config.debug = 1
proxy.GetCursOnDate(input)
The debug shows this:
*** Outgoing HTTP headers ***************************
POST /DailyInfoWebServ/DailyInfo.asmx HTTP/1.0
Host: www.cbr.ru
User-agent: SOAPpy 0.12.5 (http://pywebsvcs.sf.net)
Content-type: text/xml; charset=UTF-8
Content-length: 406
SOAPAction: "GetCursOnDate"
*****************************************************
But the service expects another value (http://web.cbr.ru/GetCursOnDate) that you can set on the proxy with an additional parameter. The following code clears the error:
from SOAPpy import SOAPProxy
from datetime import datetime
input = datetime.now()
namespace = "http://web.cbr.ru/"
url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx"
soapaction = "http://web.cbr.ru/GetCursOnDate"
proxy = SOAPProxy(url, namespace = namespace, soapaction = soapaction)
proxy.config.debug = 1
proxy.GetCursOnDate(input)
The debug will now show this:
*** Outgoing HTTP headers ***************************
POST /DailyInfoWebServ/DailyInfo.asmx HTTP/1.0
Host: www.cbr.ru
User-agent: SOAPpy 0.12.5 (http://pywebsvcs.sf.net)
Content-type: text/xml; charset=UTF-8
Content-length: 406
SOAPAction: "http://web.cbr.ru/GetCursOnDate"
*****************************************************
But although that specific fault is gone, the call won't work. Because you will return with questions I thought I'll spare us some message exchanges and write directly the sequel. I mentioned my disappointment with Python's SOAP support on another occasion. For this post I'm adding all details here as a reference to myself and hopefully as help for other users. So here it goes...
The call won't work because by default SOAPpy uses ordered parameters for the call. They are called v1, v2, v3 etc (see the MethodParameterNaming.txt file inside the SOAPpy download for more details). Your SOAP message will look like this:
<SOAP-ENV:Body>
<ns1:GetCursOnDate xmlns:ns1="http://web.cbr.ru/" SOAP-ENC:root="1">
<v1>
</v1>
</ns1:GetCursOnDate>
</SOAP-ENV:Body>
This particular web service is expecting a parameter named On_date, not v1. You can try to fix it by using named parameters:
from SOAPpy import SOAPProxy
from datetime import datetime
input = datetime.now()
namespace = "http://web.cbr.ru/"
url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx"
soapaction = "http://web.cbr.ru/GetCursOnDate"
proxy = SOAPProxy(url, namespace = namespace, soapaction = soapaction)
proxy.config.debug = 1
proxy.GetCursOnDate(On_date = input)
Your message now looks like this:
<SOAP-ENV:Body>
<ns1:GetCursOnDate xmlns:ns1="http://web.cbr.ru/" SOAP-ENC:root="1">
<On_date>
</On_date>
</ns1:GetCursOnDate>
</SOAP-ENV:Body>
I think the value of the date is missing because the proxy has an issue with datetime objects. I didn't actually check to see what the issue is with that because there is another problem with this message: the web service expects <ns1:On_date> not <On_date>.
This is where SOAPpy has some issues with namespaces. Using the original SOAPpy source code you can't change the namespaces. It seems that with most of Python's SOAP libraries you can only get your desired behavior by tweaking the code, which is what I did. I changed the SOAPBuilder.py file in some places where namespaces and tag prefixes were handled. See the original file here and the changed one here.
Those changes allow me to use a SOAPpy Type for a finer control over the message:
from SOAPpy import SOAPProxy
from SOAPpy import Types
namespace = "http://web.cbr.ru/"
url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx"
soapaction = "http://web.cbr.ru/GetCursOnDate"
input = Types.dateType(name = (namespace, "On_date"))
proxy = SOAPProxy(url, namespace = namespace, soapaction = soapaction)
proxy.config.debug = 1
proxy.GetCursOnDate(input)
Now I get the result I was looking for:
<SOAP-ENV:Body>
<ns1:GetCursOnDate xmlns:ns1="http://web.cbr.ru/" SOAP-ENC:root="1">
<ns1:On_date xsi:type="xsd:date">2013-11-02Z</ns1:On_date>
</ns1:GetCursOnDate>
</SOAP-ENV:Body>
The server returns the data on the above request.
But even the above code can be improved. Notice that I'm setting the SOAPAction on the proxy for one particular operation: GetCursOnDate. If I want to use it with another operation I need another proxy or I need to modify this one. By using a WSDL.Proxy you get this automatically from the WSDL (it provides a SOAPProxy wrapper that parses method names, namespaces and SOAPActions from the WSDL of the web service).
But even if this handles the SOAPAction automatically it doesn't pick up the namespace for the method. So I tweaked the WSDL.py file. Original version is here, changed file is here. The new client code now looks like this:
from SOAPpy import WSDL
from SOAPpy import Types
# you can download this and use it locally for better performance
wsdl = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?wsdl"
namespace = "http://web.cbr.ru/"
input = Types.dateType(name = (namespace, "On_date"))
proxy = WSDL.Proxy(wsdl, namespace = namespace)
proxy.soapproxy.config.debug = 1
proxy.GetCursOnDate(input)
For the examples above I used Python 2.6.6, SOAPpy 0.12.5, fpconst 0.7.2 and wstools 0.4.3. For others I think YMMV depending on the versions or the particular web service that you are calling. In conclusion I also want to mention that if you do a search on Google you'll notice that most people recommend SUDS instead of SOAPpy as a SOAP client so maybe have a look at that too. Good luck!
it looks like the targetNamespace is ignored but you can set a namespace per operation what works fine with soappy.
<operation name="createCall">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal" namespace="http://create.service/"/>
</input>
<output>
<soap:body use="literal" namespace="http://create.service/"/>
</output>
</operation>
of course you should use your namespace instead of http://create.service/

Categories