SOAP and REST services using the Spyne Python library

Introducing the Spyne Library


In this article I want to talk about the wonderful Spyne Python library. My acquaintance with Spyne began at the moment when I was given the task of writing a Web service that will receive and send requests through the SOAP protocol. A little googling I came across Spyne , which is a fork of the soaplib library . And I was surprised how little Russian-language information there is about this library.

With Spyne, you can write web services that can work with SOAP, JSON, YAML, and a written script can be run through mod_wsgi Apache. So, let's look at a few examples, write working scripts and configure the scripts to work through apache.

1. SOAP service


Let's write a web service that will serve us as a translator into English. Our web service will receive requests, contact Yandex-translator, receive a translation and give this translation to the client. Incoming requests in XML format are accepted. The answer will also go away in XML format.

The first step is to get the API key to tell Yandex that we are ours. How can this be done, look here .

Now we pass directly to the development.

Install the necessary libraries: "pytz", "spyne", as well as "yandex_translate". Libraries are installed very easily through pip.

The application code is as follows:

from spyne import Application, rpc, ServiceBase, Unicode
from lxml import etree
from spyne.protocol.soap import Soap11
from spyne.protocol.json import JsonDocument
from spyne.server.wsgi import WsgiApplication
from yandex_translate import YandexTranslate
class Soap(ServiceBase):
    @rpc(Unicode, _returns=Unicode)
    def Insoap(ctx, words):
        print(etree.tostring(ctx.in_document))
        translate = YandexTranslate('trnsl.1.1.201somesymbols')
        tr = translate.translate(words, 'en')
        tr_answer = tr['text'][0]
        return tr_answer
app = Application([Soap], tns='Translator',
                          in_protocol=Soap11(validator='lxml'),
                         out_protocol=Soap11()
application = WsgiApplication(app)
if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    server = make_server('0.0.0.0', 8000, application)
    server.serve_forever()

Let's analyze the code:

After importing the necessary libraries, we created the “Soap” class with the argument “ServiceBase” . The decorator "@rpc (Unicode, _returns = Unicode)" defines the type of incoming arguments ("Unicode") and outgoing responses ("_returns = Unicode") . A list of available argument types can be found in the official documentation. . Next, the Insoap method is created with the arguments ctx and words . The ctx argument is very important because it contains a lot of information about incoming requests. String "print (etree.tostring (ctx.in_document))"displays the incoming xml-request in the form in which the user sent it to us. At some points, this may be important.

For example, when writing a web service, I needed to pull out an incoming xml-request and write it to the database. But how to pull out this xml request is not mentioned in Spyne's official documentation. Burak Arslan (author of Spyne) recommended looking towards the lxml library. Only after that I found the answer and see the result in this script. Next, our method contacts the Yandex translator and returns to the client the result received from the Yandex translator.

The variable “app” defines the settings of our web service: “Application ([Soap]” - indicates which class is initialized (there may be several), parameters"In_protocol" and "out_protocol" determine the type of incoming and outgoing requests, in our case it is SOAP v1.1.

The line "application = WsgiApplication (app)" is defined so that our script can work through wsgi.

Important! the variable name must be "application" so that our application can work through apache using mod_wsgi. The subsequent lines of code initializes and starts the Web server on port 8000.

We run the script and we can start testing. For these purposes I use SoapUI . Convenience is that after starting and configuring to work with a SOAP server, SoapUI automatically generates an xml request. Configure URL: localhost : 8000? Wsdl (assuming the script is running on the local machine), and our xml request looks like this:

Xml request body
schemas.xmlsoap.org/soap/envelope »xmlns: tran =" Translator ">



Testing our application



Our web service gave the following answer:

Response from server
schemas.xmlsoap.org/soap/envelope »xmlns: tns =" ​​Translator ">


Test our app



It's simple, isn't it?

2. REST service


Suppose now we have changed those. task, and you need to make a web service that works through JSON. What to do? Rewrite our service on another framework, for example Django Rest Framework or Flask ? or can you do with less effort? Yes you can! And it is necessary!

Spyne library help us.

All that needs to be changed in our application is to bring the “app” variable to the following form:

app = Application([Soap], tns='Translator',
                          in_protocol=JsonDocument(validator='soft'),
                          out_protocol=JsonDocument())

We launch our web service and are testing.

Our JSON request looks like this:

JSON request body
{"Insoap": {"words": "testing our web service. We use JSON "}}

The web server returned the following response:

Web server response
"Test our web service. Use JSON »

3. Conclusion in production


To run our web service via apache, you need to install and configure the apache and mod_wsgi web server on the server . These works are easy to perform, based on the documentation. In addition, in our script, we must delete the following lines:

Rows to delete
if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    server = make_server('0.0.0.0', 8000, application)
    server.serve_forever()


Hurrah! Our web service is ready to use in operation.

PS about the additional features of Spyne (and there are many of them) can always be found on the official website , which I highly recommend to you.

Also popular now: