Чтобы показать, как работают веб-сервисы, обращаться к которым можно по протоколу SOAP, зачем нужен WSDL, и как это связано с XML-документом в теле полезной нагрузки POST-запроса, сегодня я напишу простое Python-приложение для работы с поставщиками.
Еще раз о том, что такое SOAP и чем он отличается от REST
Хотя вопрос «Чем отличается REST от SOAP» является чуть ли не самым популярным в собеседованиях на роль системного аналитика, мне он напоминает попытку сравнить круглое с зеленым. Начнем с того, что REST API – это архитектурный стиль разработки веб-приложения, тогда как SOAP – это строгий протокол обмена структурированными XML-сообщениями в распределённой вычислительной среде (Simple Object Access Protocol). Он расширяет протокол XML-RPC и работает поверх протоколов прикладного уровня: SMTP, FTP, HTTP, HTTPS и пр.
REST как архитектурный стиль не имеет строгих стандартов использования типовых HTTP-методов (GET, POST, PUT, PATCH, DELETE) для операций над ресурсами, позволяя разработчику реализовать бизнес-логику приложения в рамках такой ресурсной модели. SOAP имеет множество стандартов и расширений (WS-Security для безопасности, WS-AtomicTransaction для транзакций), что делает его более подходящим для приложений со сложной бизнес-логикой и транзакционных операций.
В качестве примера рассмотрим веб-сервис оценки поставщика, который вычисляет его рейтинг надежности в зависимости от характеристик компании и назначает зону доставки в зависимости от адреса. Процесс взаимодействия пользователя с такой клиент-серверной системой выглядит так.
PlantUML-скрипт для этой диаграммы:
Веб-сервис, общение с которым реализуется через SOAP, обычно имеет 1 конечную точку, т.е. один URL-адрес, на который отправляется HTTP-запрос POST с полезной нагрузкой в виде SOAP-сообщения. Это SOAP-сообщение всегда представляется в формате XML и имеет древовидную тегированную структуру. Например, для оценки надежности поставщика в моем SOAP-сервисе оно выглядит так.
Формат XML позволяет описывать сложные структуры данных с помощью иерархии вложенных тегов. Можно расширять XML-документы, определяя собственные теги, и строить из них сложные иерархические структуры, соблюдая принцип декомпозиции. Общая схема данных для XML-документа описывается в XSD (XML Schema Definition), где задаются элементы и атрибуты XML, их типы, порядок, количественные и содержательные ограничения. Подробнее о том, что такое схема данных и чем она отличается от формата сериализации, я писала здесь.
Поскольку XML является довольно строгим, хотя и расширяемым форматом данных, неудивительно, что именно он используется в строгом протоколе SOAP. Поскольку межсистемная интеграция по SOAP реализует принципы удаленного вызова процедур (RPC, Remote Procedure Call), клиенту, инициирующему взаимодействие, надо знать, какие функции он может вызвать на удаленном сервере и с какими параметрами. Это описывается в WSDL-документе (Web Services Description Language), тоже представленном в формате XML. WSDL содержит определение типов данных отправляемых и получаемых веб-сервисом SOAP-сообщений, какие операции могут быть с ними выполнены, конечную точку обращения к веб-сервису и привязки – способы доставки сообщений.
В отличие от схемы полезной нагрузки, т.е. SOAP-сообщения, WSDL-документ не создается аналитиком или разработчиком вручную, а генерируется из программного кода веб-сервиса. Например, Python-библиотека Spyne автоматически генерирует WSDL-документ на основе определённых в коде сервисов и типов данных. Пример этого кода и тестирование сервиса через Postman рассмотрим далее.
Реализация SOAP-сервиса на Python
Разумеется, лучше вести разработку в локальной IDE, например, PyCharm или VSCode, разворачивая приложения на локальном хосте. Но, чтобы вы могли повторить эту работу без установки IDE, приведу Python-код для запуска в интерактивной среде Google Colab. Сперва установим библиотеки, необходимые для работы с XML, создания веб-приложений и веб-сервисов, а также для туннелирования сокета, на котором развернуто SOAP-приложение, запущенное на конкретном порту локального хоста виртуальной машины Google Colab, чтобы к нему можно было обратиться извне. При работе на локальном хосте ngrok не нужен, а инструкции установки пакетов зависят от самой IDE. Однако, для Colab это выглядит так:
Далее импортируем модули и функции для создания и запуска веб-сервиса.
Установим личный токен утилиты тунелирования ngrok, полученный на платформе https://dashboard.ngrok.com/
Создадим публичный URL-адрес с помощью ngrok, чтобы веб-сервис с локального хоста был доступен извне:
Объявим класс SupplierService, который наследуется от базового класса ServiceBase. В библиотеке Spyne класс ServiceBase является базовым для всех определений служб, т.е. содержит общие свойства и методы, необходимые для работы с веб-сервисом.
Этот класс содержит два метода:
- assess_reliability – оценка надежности поставщика по различным критериям (организационно-правовая форма бизнеса, время существования в годах, количество сотрудников, наличие офиса и склада);
- assign_delivery_zone – назначение зоны доставки на основе адреса поставщика с указанием административного округа Москвы.
Декоратор @rpc выставляет методы как удаленные вызовы процедур и объявляет типы данных, которые он принимает и возвращает, а также передает экземпляр контекста метода Spyne-библиотеки spyne.MethodContext в качестве первого аргумента вызываемой функции.
Далее создадим Flask-приложение и свяжем его с библиотекой Spyne для обработки SOAP-запросов.
В этом коде помимо указания протокола SOAP версии 1.1 для входящих и исходящих сообщений веб-сервиса, валидации входящих сообщений с помощью библиотеки lxml также указано целевое пространство имен, tns (target namespace). В данном случае tns=’spyne.examples.supplier’ обозначает уникальный идентификатор пользовательского пространства имен, которое далее будет указываться во входящих и исходящих SOAP-сообщениях, что мы посмотрим далее. Задавать пространство имен нужно, чтобы избежать конфликтов между разными веб-сервисами.
Для взаимодействия веб-сервера и серверного веб-приложения на Python используется стандарт интерфейса WSGI (Web Server Gateway Interface). Он позволяет веб-приложениям взаимодействовать с веб-серверами независимым от конкретного сервера способом.
Для синхронного взаимодействия с веб-сервисом определим функцию start_response, которая создает и возвращает объект Response, используя параметры, переданные при вызове функции.
Далее определим конечные точки SOAP-сервиса, т.е. маршруты с помощью декоратора @app.route, и методы обращения к ним.
Хотя для удаленных процедур, которые клиент может вызвать на сервере, используется 1 конечная точка, для доступа к WSDL-документу этой SOAP-службы добавлена вторая.
Для непосредственного развертывания Flask-приложения запустим его на порту 5000:
Весь код можно, как обычно, посмотреть в моем Github-репозитории: https://github.com/AnnaVichugova/PythonApps/blob/main/SOAP.
После запуска представленного скрипта можно кликнуть на туннелированный URL, новый при каждом запуске, и в браузере откроется веб-сервис.
Для удобства работы с этой демонстрацией при отправке GET-запроса к главному маршруту на HTML-странице я решила вывести примеры SOAP-сообщений, которые можно отправить POST-запросом к веб-сервису.
Далее можно протестировать этот веб-сервис через Postman, отправив POST-запрос к этому URL с полезной нагрузкой в виде XML-сообщения SOAP. Например, для получения оценки надежности поставщика это SOAP-сообщение может выглядеть так:
В этом сообщении определены атрибуты пространства имен xmlns (XML namespace – пространство имен): универсальное пространство имен SOAP и пользовательское пространства имен spyne.examples.supplier, ранее указанное в коде самого приложения.
Поскольку непосредственно сама полезная нагрузка данных о поставщике может включать спецсимволы, например, кавычки и пр., которые интерпретируются как часть синтаксиса XML, эти поля заключены в секцию CDATA-секция (Character Data), которая НЕ обрабатывается XML-парсером, а разбираются методами Python-библиотеки lxml и ее модуля etree.
Для вычисления зоны доставки надо отправить такое SOAP-сообщение:
Разумеется, теги в теле SOAP-сообщения, в которых заключены передаваемые на сервер данные, должны соответствовать объектам в коде, полученным из строковых значений после парсинга входящего XML-документа. В частности, функция etree.fromstring() из библиотеки lxml принимает строку XML и парсит её в дерево XML-элементов, чтобы работать с XML-структурой как с объектами. Метод find() дерева XML-элементов ищет в нем первый элемента с указанным тегом, а его атрибут text возвращает текстовое содержимое найденного элемента.
Таким образом, веб-сервис разбирает (парсит) входящее SOAP-сообщение, извлекает содержащиеся в нем данные и передает их в соответствующие методы серверного приложения. Результаты этих вызовов упаковываются в ответное SOAP-сообщение, которое отправляется обратно клиенту. Сопоставление значений тегов SOAP-сообщения с переменными в коде выполняется с помощью десериализаторов, которые преобразуют XML-данные в объекты. При этом можно валидировать типы передаваемых данных, например, с помощью XSD-схемы XML-документа, передаваемого в теле SOAP-сообщения. Все это: названия удаленных методов, их параметры, типы передаваемых и возвращаемых значений, отражается в WSDL-документе. Просмотреть этот WSDL-документ в моем примере можно, просто обратившись GET-запросом HTTP к ресурсу /wsdl, добавив это к URL-адресу, сгенерированного с помощью утилиты ngrok для запущенного SOAP-приложения.
Этот WSDL-документ, сгенерированный из кода SOAP-приложения средствами Python-библиотеки Spyne, можно далее использовать для интеграции внешних систем с разработанным веб-сервисом. Причем не только для этапа проектирования как документацию, но и для непосредственной реализации, сгенерировав классы клиентского приложения на основе WSDL, например, с помощью SOAP-клиента zeep для Python или модуля wsdl2java фреймворка Apache CXF для Java.
Надеюсь, что эта небольшая демонстрация с разбором особенностей реализации веб-сервиса помогла вам понять основные принципы межсистемной интеграции по протоколу SOAP, а также разобраться с назначением и содержанием XML, XSD и WSDL-документов.
Больше примеров и подробностей про архитектуру и интеграцию информационных систем вы узнаете на моих курсах в Школе прикладного бизнес-анализа на базе нашего лицензированного учебного центра обучения и повышения квалификации системных и бизнес-аналитиков в Москве:
Курс: OAIS
Копирование, размножение, распространение, перепечатка (целиком или частично), или иное использование материала допускается только с письменного разрешения правообладателя ООО "УЦ Коммерсант"