Удобные и простые решения проблем при интеграции с серверными мощностями — что делать, если возникает задача сделать два продукта, которые бы идеально стыковались, предоставляли бы друг другу консистентные данные и сами по себе работали без сбоев.
С подробностями Егор Тафланиди, Redmadrobot.
Если вы не создаёте самодостаточный продукт (а таких на мобильных платформах в действительности совсем мало), вы создаёте так называемое «бизнес»-приложение, за спиной которого обычно стоит сервер, предоставляющий актуальные данные и решающий некоторые трудоёмкие задачи.
Связка сервер/клиент настолько прочно вросла в среду мобильной разработки, что современный «умный телефон» без подключения к интернету может просто превратиться в кирпич. Некоторые библиотеки и framework'и (типа RhoMobile/RhoConnect) в своей сути строятся вокруг этой самой сервер/клиент интеграции, оставляя её глубоко «под капотом».
Существует множество подходов к реализации подобной архитектуры (два продукта, которые бы идеально стыковались, предоставляли друг другу консистентные данные и сами по себе работали без сбоев).
- Разработку можно доверить одному человеку (или же тесно сотрудничающей команде, сидящей в одной комнате – это одно и то же). Он сам состыкует все необходимые узлы и максимально эффективно решит все возникающие проблемы интеграции.
- Вы можете отдать реализацию сервера своим партнёрам, занимающимся разработкой серверного ПО.
- У заказчика может быть своя команда серверных разработчиков – так часто бывает в случаях сотрудничества с банками.
Какой бы вариант вы не выбрали, к сожалению, зачастую даже чётко прописанная спецификация протокола взаимодействия сервер/клиент не может обеспечить корректную интеграцию. И перед вами возникнет простая, очевидная проблема: протоколы клиента и сервера не совпадают.
С точки зрения разработки клиента это приводит к тому, что мобильное приложение получает некорректные данные. Или же не получает их вовсе.
Если архитектурный дизайн недостаточно «пуленепробиваем», и времени на разработку было выделено мало – приложение будет «падать», отображать белиберду и вообще вести себя некрасиво.
Соответственно, не гарантируется корректность обратной связи: кто сказал, что сериализованные данные от вашего приложения будут адекватно распознаны на сервере?
Как быть?
Первым на ум приходит подленькое решение подогнать все парсеры и сериализаторы в мобильном приложении под то, что уже приходит с сервера.
Вы получаете какой-нибудь JSON, вроде этого:
{ data: { “field1”: “value1”, “filed2”: “value2” } }
Вместо того, что прописан в спецификации:
{ data: { “entity”: { “field1”: “value1”, “filed2”: “value2” } } }
Ценная информация – “field1” и “field2” как бы и так приходит. Так почему бы не допустить небольшую хитрость — вычитывать информацию из того, что уже предоставлено?
Я уже упоминал ключевое слово «консистентность». Дословно с английского «консистентно выполнять» = «последовательно выполнять», в том смысле что «придерживаться заданной линии поведения».
Например, если изначально какое-то явление было обозвано «phenomenon», то оно и в документации должно именоваться «phenomenon», и в исходном коде должно быть классом «Phenomenon», и в приходящих JSON’ах должно иметь ключ «phenomenon».
Когда все участники проекта используют один и тот же глоссарий – это значительно снижает риски недопонимания.
Рано или поздно кто-то из разработчиков может обнаружить несоответствие документации – и исправить. И с другой стороны системы всё обрушится.
Кроме того, на основе уже написанной документации для сервера впоследствии могут создаваться другие клиенты под другие мобильные и, возможно, desktop-платформы – и они будут натыкаться на эти же проблемы: реализация не соответствует документации.
Это приведет к тому, что система начнёт обрастать костылями и гнить изнутри.
Решения
Небольшой сервис — очень простой и довольно ограниченный в своей функциональности, но этим же и привлекательный. Он предоставляет макетную реализацию вашего API.
Вы получаете уникальный URL, на который можете натравить своё мобильное приложение. В комплекте идёт аккуратная документация по всем реализованным макетным веб-сервисам плюс типичные ответы, которые от этих веб-сервисов должны приходить.
Например, вам необходим сервер, который будет отдавать набор каких-то сущностей Entity. Список пользователей, список ресторанов, список банкоматов – не важно.
У каждой сущности есть свой ID, по которому сервер должен уметь предоставлять подробную информацию о данной сущности.
Плюс API должен отдельно предоставлять, скажем, служебную информацию – поле timestamp – время обновления сущности с заданным ID.
Итак, мы предполагаем, что у нас есть:
Адрес
Сервис 1:
- на GET-запрос отдаёт набор сущностей
- на POST-запрос отдаёт подтверждение добавления новой сущности
Сервис 2:
- на GET-запрос отдаёт подробную информацию о сущности;
- на UPDATE-запрос отдаёт подтверждение обновления сущности
(небольшая оговорка: к сожалению, apiary.io не позволяет реализовать полноценный REST, поэтому отдавать на UPDATE-запрос обновлённую сущность вряд ли получится).
Сервис 3:
- на GET-запрос отдаёт дату последнего обновления сущности.
И т.д.
Пример подобного «сервера» находится здесь.
Описание макетных сервисов крайне простое и носит декларативный характер.
При создании нового макетного API вам сразу предоставляется пример:
FORMAT: 1A HOST: http://www.application.com # application Notes API is a *short texts saving* service similar to its physical paper presence on your table. # Group Notes Notes related resources of the **Notes API** ## Notes Collection [/notes] ### List all Notes [GET] + Response 200 (application/json) [{ "id": 1, "title": "Jogging in park" }, { "id": 2, "title": "Pick-up posters from post-office" }] ### Create a Note [POST] + Request (application/json) { "title": "Buy cheese and bread for breakfast." } + Response 201 (application/json) { "id": 3, "title": "Buy cheese and bread for breakfast." }
Данный код описывает работу сервиса, отвечающего на GET- и POST-запросы.
И сам сервис apiary.io может выступать в роли прокси. Посредством одного переключателя вы можете перенаправить весь трафик, приходящий на макетный сервер, на «боевой» back-end, не меняя ничего в исходном коде клиента.
Казалось бы, всё хорошо, всё красиво, сервис позволяет команде работать без блокировки процесса, предоставляет удобный скриптовый язык…
Проблема в том, что особой логикой он, увы, не обладает.
Можно сымитировать возвращение сущности в зависимости от её ID, но в любом случае это будет конечный автомат, не способный сколько-нибудь анализировать ситуацию – у него слегка другое предназначение.
http://www.soapui.org
Если вам необходимо копнуть чуть глубже – не беда. Всегда есть старый, проверенный Soap UI.
SoapUI является мультизадачным комбайном, изначально предназначенным и нацеленным на тестирование SOAP- и REST-сервисов в автоматическом режиме. Кроме всего прочего, он сам умеет выступать в роли соответствующего сервера и предоставлять макетные данные.
Инструкция к действию:
Создаём проект и выпиливаем из него всё лишнее
Создаём новый макетный REST-сервис
Добавляем action
Пусть возвращает список Entities
Добавляем макетные данные
Пусть сервис возвращает этот список только по наличию авторизационного ключа.
Добавляем ответ для «неавторизованного» пользователя
Переключаем Dispatch-режим в состояние “SCRIPT” и копируем один из приведенных примеров проверки параметров запроса
Запускаем (предварительно проверив порт в настройках сервиса; по умолчанию – 8080)
Проверяем
Всё, макетный сервер готов.
Выводы
Естественно, приведенный сервис – не единственный, и существует ряд его аналогов, типа mockable.io, предоставляющих схожий функционал.
Увы, у большинства подобных решений обычно недостаёт гибкости в плане реализации полноценной реакции на возможные сетевые запросы.
Действительно функциональных и удобных сервисов для создания макетных API – не так уж и много.
С другой стороны, простота подобных решений обеспечивает их относительно быстрое развёртывание, и на каком-то этапе реализации проекта это может стать решающим фактором.
Так, apiary.io вполне может быть задействован при создании прототипа или proof-of-concept-решения, а по мере эволюционирования проекта уже можно думать о последующем переезде на более продвинутые сервисы с логикой, скриптами…
А там глядишь – уже и боевой сервер готов.
Отдельной статьёй, конечно, идут BAAS-сервера, но это уже слегка другая история.
А как вы решаете проблемы интеграции?
Автор: redmadrobot