https://habrahabr.ru/post/334290/- Разработка под Linux
- Python
Знакомство с библиотекой Spyne
В данной статье я хочу рассказать о замечательной Python-библиотеке Spyne.
Мое знакомство с Spyne началось в тот момент, когда передо мной поставили задачу написать Веб-сервис, который будет принимать и отдавать запросы через SOAP-протокол. Немного погуглив я наткнулся на
Spyne, которая является форком библиотеки
soaplib. А еще я был удивлен, насколько мало русскоязычной информации встречается о данной библиотеке.
С помощью Spyne можно писать веб-сервисы, которые умеют работать с SOAP, JSON, YAML, а написанный скрипт можно запустить через mod_wsgi Apache. Итак, давайте рассмотрим несколько примеров, напишем работающие скрипты и настроим так, чтобы скрипты работали через apache.
1. SOAP-сервис
Давайте напишем веб-сервис, который будет служить нам переводчиком на английский язык. Наш веб-сервис будет получать запросы, обращаться в Yandex-translator, получать перевод и данный перевод отдавать клиенту. Принимаются входящие запросы в XML-формате. Ответ также будет уходить в XML-формате.
Первым делом необходимо получить API-ключ, чтобы сказать Яндексу, что мы свои. Как можно это сделать, смотрим
тут.
Теперь переходим непосредственно к разработке.
Устанавливаем необходимые библиотеки: «pytz», «spyne», а также «yandex_translate». Библиотеки ставятся очень легко через pip.
Код приложения выглядит следующим образом:
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()
Разберем код:
После импортирования необходимых библиотек, мы создали класс
«Soap» с аргументом
«ServiceBase». Декоратор
"@rpc(Unicode, _returns=Unicode)" определяет тип входящих аргументов
(«Unicode») и исходящих ответов
("_returns=Unicode"). Список доступных типов аргументов можно посмотреть в
официальной документации.. Далее создается метод
«Insoap» с аргументами
«ctx» и
«words». Аргумент
«ctx» очень важен, так как в нем содержится много информации о входящих запросах. Строка
«print(etree.tostring(ctx.in_document))» выводит на экран входящий xml-запрос, в таком виде, в каком нам его отправил пользователь. В некоторых моментах это может быть важно. Например, мне в ходе написания веб-сервиса нужно было вытащить входящий xml-запрос и записать в базу данных. Но как вытащить этот xml-запрос не упомянуто в официальной документации Spyne. Burak Arslan (автор Spyne) порекомендовал смотреть в сторону библиотеки lxml. Только после этого я нашел ответ и результат видите в данноме скрипте. Далее наш метод обращается в Яндекс-переводчик и возвращает клиенту полученный от Яндекс-переводчика результат.
Переменная
«app» определяет настройки нашего веб-сервиса:
«Application([Soap]» — указывается, какой класс инициализируется (их может быть несколько), параметры
«in_protocol» и
«out_protocol» определяет тип входящих и исходящих запросов, в нашем случае это SOAP v1.1.
Строкой
«application = WsgiApplication(app)» определяется, чтобы наш скрипт мог работать через wsgi.
Важно! имя переменного обязательно должен быть «application», чтобы наше приложение мог работать через apache с помощью mod_wsgi.
Последующие строки кода инициализирует и запускает Веб-сервер по порту 8000.
Запускаем скрипт и можно приступать к тестированию. Для этих целей я использую
SoapUI. Удобство состоит в том, что после запуска и настройки для работы с SOAP сервером, SoapUI автоматически формирует xml-запрос. Наш xml-запрос выглядит следующим образом:
Тело xml-запроса<soapenv:Envelope xmlns:soapenv=«
schemas.xmlsoap.org/soap/envelope» xmlns:tran=«Translator»>
<soapenv:Header/>
<soapenv:Body>
<tran:Insoap>
<tran:words>Тестируем наше приложение</tran:words>
</tran:Insoap>
</soapenv:Body>
</soapenv:Envelope>
Наш веб-сервис дал следующий ответ:
Ответ от сервера<soap11env:Envelope xmlns:soap11env=«
schemas.xmlsoap.org/soap/envelope» xmlns:tns=«Translator»>
<soap11env:Body>
<tns:InsoapResponse>
<tns:InsoapResult>Test our app</tns:InsoapResult>
</tns:InsoapResponse>
</soap11env:Body>
</soap11env:Envelope>
Все просто, не правда ли?
2. REST-сервис
Предположим, что теперь у нас поменялось тех. задание, и нужно сделать веб-сервис, который работает через JSON. Что делать? Переписывать наш сервис на другом фреймворке, например
Django Rest Framework или
Flask? или можно обойтись меньшими усилиями? Да, можно! И нужно!
Библиотека Spyne нам в помошь.
Все что потребуется поменять в нашем приложении, это переменную «app» привести к следующему виду:
app = Application([Soap], tns='Translator',
in_protocol=JsonDocument(validator='soft'),
out_protocol=JsonDocument())
Запускаем наш веб-сервис и тестируемся.
Наш JSON-запрос выглядит так:
Тело JSON-запроса{«Insoap»: {«words»:«тестируем наш веб-сервис. Используем JSON»}}
Веб сервер вернул следующий ответ:
Ответ веб-сервера«test our web service. Use JSON»
3. Вывод в продакшн
Для запуска нашего веб-сервиса через apache, необходимо на сервер установить и настроить веб-сервер
apache и
mod_wsgi. Данные работы несложно выполнить, опираясь на документацию. Кроме этого, в нашем скрипте мы должны удалить следующие строки:
Строки для удаленияif __name__ == '__main__':
from wsgiref.simple_server import make_server
server = make_server('0.0.0.0', 8000, application)
server.serve_forever()
Ура! Наш веб-сервис готов к использованию в эксплуатации.
P.S. о дополнительных возможностях Spyne (а их немало) всегда можно ознакомиться на
официальном сайте, чего я вам очень рекомендую.