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 токен приложений,
сгенерированный ранее.
Для успешного добавления записи имеющегося в модели данных типа объекта в запросе должны содержаться все обязательные поля для данного типа объекта.
Процедура отправки запроса и ожидаемые результаты описаны ранее в пункте Отправка запросов.