3.1.5. Запросы в формате XML (SOAP)¶
Рассмотрим обработку запросов в формате XML (SOAP) на основе базового примера. Для отправки запросов мы используем простые скрипты на языке Python. Для приёма и обработки запросов нам понадобится кластер TDG, настроенный ранее.
3.1.5.1. Адаптация конфигурации из базового примера¶
Для повторения примеров из данного раздела нам потребуется внести определенные исправления в конфигурацию системы, загруженную ранее.
Разархивируйте архив с конфигурацией системы в отдельную директорию.
Откройте файл config.yml
и измените его так, чтобы он содержал следующий текст:
types:
__file: model.avsc
functions:
router: {__file: router.lua}
classifier: {__file: classificator.lua}
select_user_books: {__file: select_user_books.lua}
process_user: {__file: process_user.lua}
process_book: {__file: process_book.lua}
process_sub: {__file: process_sub.lua}
pipelines:
router:
- router
classifier:
- classifier
select_user_books:
- select_user_books
process_user:
- process_user
process_book:
- process_book
process_sub:
- process_sub
connector:
input:
- name: soap
type: soap
wsdl: {__file: example.wsdl}
handlers:
- function: Connect
pipeline: router
routing:
- key: input_key
output: to_input_processor
output:
- name: to_input_processor
type: input_processor
input_processor:
classifiers:
- name: classifier
pipeline: classifier
routing:
- key: process_user
pipeline: process_user
- key: process_book
pipeline: process_book
- key: process_sub
pipeline: process_sub
storage:
- key: add_user
type: User
- key: add_book
type: Book
- key: add_subscription
type: Subscription
services:
select_user_books:
doc: "select_user_books"
function: select_user_books
return_type: string
args:
user_id: long
Обратите внимание на появившийся раздел input_processor
/routing
и связанные
с ним описания новых конвейеров обработки данных (pipeline) и функций. При этом
модель данных не изменилась. В разделе connector
появилось описание входа с
типом SOAP, функцией Connect
(не являющейся функцией TDG, но описываемой
в XML/SOAP) и связанным с ней конвейером (уже известным нам по примеру с JSON — router
).
Примечание
В секции wsdl:
обязательно указывается файл спецификации веб-сервиса с
расширением .wsdl
. В нашем примере это example.wsdl
. Данный файл должен
обязательно быть включен в состав архива с конфигурацией системы. В том случае,
если WSDL не используется, данный файл может быть пустым.
Теперь откройте файл classificator.lua
и отредактируйте его так, чтобы он имел
следующее содержимое:
#!/usr/bin/env tarantool
local param = ...
if (param.obj[1].tag == "username" or param.obj[2].tag == "username") then
param.routing_key = "process_user"
return param
end
if (param.obj[1].tag == "book_name" or param.obj[2].tag == "book_name") then
param.routing_key = "process_book"
return param
end
if ((param.obj[1].tag == "user_id" and param.obj[2] == "book_id") or (param.obj[2].tag == "user_id" and param.obj[1].tag == "book_id")) then
param.routing_key = "process_sub"
return param
end
param.routing_key = "unknown_type"
return param
Создайте файлы process_user.lua
, process_book.lua
и process_sub.lua
.
Содержимое этих файлов — скрипт обработки данных, который должен формировать из
получаемого TDG информационного объекта объект, соответствующий описанному
в модели данных.
Далее приведен пример содержимого файла process_user.lua
.
Остальные файлы выполняются по аналогии.
#!/usr/bin/env tarantool
local param = ...
local id = param.obj[1][1]
local username = param.obj[2][1]
local data = {id = tonumber(id), username = username}
local ret = {obj = data, priority = 1, routing_key = 'add_user'}
return ret
Сформированный вышеуказанным скриптом объект должен содержать поля id
и username
,
так как он получит routing_key
для добавления объекта типа User
в хранилище.
Важно
Для сохранения TDG ожидает объект в формате, представленном выше,
где obj
включает в себя весь информационный объект в виде перечисленных
через запятую пар key = value
, где для каждого обязательного поля объекта
в модели данных задан одноимённый ключ (key) с непустым значением.
Закончив с подготовкой файлов, упакуйте их в zip-архив и загрузите его согласно инструкции.
3.1.5.2. Описание процесса обработки запроса¶
Логика обработки поступающего запроса изложена в файле конфигурации config.yml
и состоит в следующем:
Согласно разделу
connector
/input
файла конфигурацииconfig.yml
, SOAP (XML) запросы передаются на обработку конвейеруrouter
, который состоит из функцииrouter
;Функция
router
ссылается на файлrouter.lua
, который упаковывает поступивший объект с ключомrouting_key
равным строкеinput_key
;Согласно разделу
connector
/routing
файла конфигурацииconfig.yml
, все объекты с ключомinput_key
передаютсяto_input_processor
;В секции
output
для разделаconnector
указана единственная записьto_input_processor
, которая переадресует запрос в разделinput_processor
для обработки на одноименной роли;В разделе
input_processor
все запросы попадают в секциюclassifiers
, где в нашем случае указан один единственный объект, вызывающий конвейер обработки объектов (pipeline)classifier
;Конвейер
classifier
вызывает одноименную функцию, которая описана в файлеclassificator.lua
. Как можно понять из названия, данная функция занимается классификацией поступающей информации. Логика ее работы следующая:при наличии тэга
username
у поступившего объекта — ему присваиваетсяrouting_key
=process_user
, то есть объект направляется для формирования объекта типа пользователь;при наличии тэга
book_name
у поступившего объекта — ему присваиваетсяrouting_key
=process_book
, то есть объект направляется для формирования объекта типа книга;при наличии тэгов
user_id
иbook_id
у поступившего объекта — ему присваиваетсяrouting_key
=process_sub
, то есть объект направляется для формирования объекта типа подписка;во всех остальных случаях объекту присваивается
routing_key
=unknown_type
, то есть объект не распознан. Такой объект обычно попадает в ремонтную очередь, но можно настроить и иное поведение;
В разделе
input_processor
в секцииrouting
имеются указания по обработке объектов со следующимиrouting_key
:process_user
,process_book
иprocess_sub
при помощи одноименных функций. Каждая из этих функций формирует объект в нужном для сохранения формате и присваивает ему соответствующийrouting_key
;В секции
storage
описано сохранение данных в TDG.при значении
routing_key
равномadd_user
объект сохраняется какUser
;при значении
routing_key
равномadd_book
объект сохраняется какBook
;при значении
routing_key
равномadd_subscription
объект сохраняется какSubscription
.
Обратите внимание, что вся лишняя информация, не относящаяся к типу объекта, описанному в модели данных, не будет сохранена.
Из всего файла конфигурации системы остался не рассмотренным участок, отвечающий
за сервисы. В данном примере там описан простой сервис, вызывающий функцию select_user_books
с аргументом user_id
и возвращающий строковую переменную.
Логика работы этой функции такова — переданное значение user_id
используется
для поиска в объекте Subscription
всех книг, записанных за данным пользователем.
Затем выводятся все найденные book_id
.
3.1.5.3. Подготовка запроса в формате SOAP (XML)¶
Создайте файл request.py
со скриптом на языке Python для отправки простейшего
запроса с полями объекта типа User
(из нашей модели данных:
это поля id
и username
), который будет выглядеть следующим образом:
import requests
data = """<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<NS2:Connect xmlns:NS2="http://172.19.0.2:8080/soap">
<id>1</id>
<username>John Smith</username>
</NS2:Connect>
</soap:Body>
</soap:Envelope>"""
header = {'Authorization' : 'Bearer c0b26a60-aebe-4899-9ab6-4458627ac61e'}
r = requests.post(url = "http://172.19.0.2:8080/soap", data = data, headers = header)
Передаваемый запрос содержит заголовок для авторизации и тело в виде
SOAP объекта с обязательными полями для объекта модели данных типа User
.
Примечание
Используйте в качестве значения для параметра Authorization: Bearer
токен приложений,
сгенерированный ранее.
Для успешного добавления записи имеющегося в модели данных типа объекта в запросе должны содержаться все обязательные поля для данного типа объекта.
Процедура отправки запроса и ожидаемые результаты описаны ранее в пункте Отправка запросов.