Mobile API =============== ### Документация При разработке API половина дела - это документация. На проекте ИГС мы пришли к следующему формату. В конфлюенсе для каждой фичи заводим таблицу: **Экран** | **Описание** | **API** | **АИС** Одна строка - один экран. **Экран** - скриншоты дизайна экрана приложения **Описание** - словесное описание логики экрана + опционально тест-лист от QA **API** - пример запроса-ответа, назначение каждого поля с указанием типа данных, обязательности передаваемых и возвращаемых полей **АИС** - входная документация от заказчика. Может понадобиться QA Я стремлюсь к тому, чтобы для одного экрана было не более одного запроса API. К примеру, один из запросов API может вызывать 6 методов SOAP-сервиса. Также разработчики МП говорят спасибо, если структура и порядок данных максимально соответствуют дизайну. ### Свагер + postman Для API автоматически генерируется описание swagger и настроен swagger-ui. В основном это нужно для того, чтобы понимать актуальное состояние API - выкатили метод/поле или нет и на какое оркужение. > В iOS разработчики используют порочную практику генерации кода сетевого клиента из swagger.json. Если кратко, то проблема в том, что сгенеренный код - черный ящик. Также в swagger.json протекают названия DTO, что при рефакторинге API выливается в неожиданные доработки на стороне iOS. > > Если у вас будет тоже самое, то нужно подумать, как зафиксировать названия DTO при генерации swagger.json Swagger для .NET имеет недоработки, например, не помечает поля deprecated, возможно, в java таких проблем нет. Это решается при помощи описания в конфлюенсе актуального состояния. Для работы с запросами мы с QA используем единую учетку Postman и шарим коллекции и историю запросов. Postman гораздо удобнее свагера, например, из-за окружений и переменных. ### Соглашения Прописано в шапке swagger-ui, дословно: ``` Даты: Поля с суффиксом _date передаются в формате dd.mm.YYYY. Такие даты нельзя пересчитывать по часовому поясу Поля с суффиксом _date_time передаются в формате DateTime ISO Стоимость: Поля с суффиксом _amount - это денежная сумма, нужно парсить без потери точности (вероятно в decimal) Возврат ошибок: Все ответы с кодом кроме 200 OK нельзя парсить, поскольку в теле ответа содержится только диагностическая информация, не предназначенная для использования на клиенте Идентификаторы _id и id - тип string ``` ### Формат В случае ИГС SOAP-сервис присылает различное безобразие: Y, N, 1, 0 для булева типа, М, Ж, муж - для пола, тип double для идентификаторов, даты разных сортов и прочее. Я все по-максимуму привожу к унифицированным enum'ам и нормальным типам данных - string для id, boolean для булов, даты в iso формате. Если в SOAP нужно передавать ФИО целой строкой, то в API есть отдельно FirstName SecondName LastName, которые склеиваются в API и передаются дальше. Для массивов приходит пустой массив место null. И так далее. Все эту косметику Саша П называет "чтобы все было по фэншую". Ошибки наш SOAP-сервис отдает в кастомном формате и по ним нет толковой документации, но скорее всего можно узнать, какие коды ошибок соответствуют: * Status400BadRequest * Status401Unauthorized * Status403Forbidden * Status503ServiceUnavailable * Как отличать бизнес-ошибку Для таймаутов SOAP-сервиса у нас отдается 504 ошибка для понимания ситуации. Формат респонза API: { "header": { "error_code": 0, "error_message": "string", }, "data": { ... } } Для МП получается прозрачная логика работа с ошибками Если Http Status Code != 200 - то ошибка сервера, приложение показывает примерно следующий алерт "что то пошло не так, сообщите на саппорт". Если ошибка 503, то "пожалуйста, подождите, сервис скоро продолжит свою работу" Если Http Status Code == 200 и error_code != 0 - то это бизнес-ошибка, показываем диалог с содержимым error_message. Если Http Status Code == 200 и error_code == 0 - то все ок, можно смотреть, что пришло в data. ### Changelog На каждую сборку настроен CI, который после деплоя API получает его swagger.json и заливает этот файл в другой репозиторий. С этого репозитория падает нотификашка на каждый коммит в отдельный канал в слаке. Таким образом можно видеть изменения методов и полей. Это помощь прежде всего самому себе, так как для всех изменений лучше заводить задачу или стикер на доску, иначе мобильщики что-нибудь пропустят. Помимо этого при мерже правок на демо окружение я создаю в конфлюенсе страницу changelog с таблицей следующего формата: **Method** | **Request** | **Response** | **iOS** | **Android** **Method** - uri метода **Request** - словесное описание изменений в реквесте метода. Иногда сожержит подсказку для QA как проверять. **Response** - словесное описание изменений в респонзе метода. Иногда сожержит подсказку для QA как проверять. **iOS** | **Android** - заполняет QA при проверке. ### Моки API Моки нужны по нескольким причинам: * они работают быстрее, это экономия времени для разработчиков приложения * внешний сервис крайне нестабилен * заказчик долго предоставляет тестовые данные Для моков у нас используется mock-server.js. Его код и стабы хранятся в gitlab, в gitlab есть удобный web ide, так что любой участник проекта в теории может быстро добавить нужный мок на общий мок-сервер либо запустить свой локальный мок-сервер. На практике только единицы отважились этим воспользоваться. Возможно, подход с apiary более жизнеспособный. На эту тему у нас висят в бэклоге еще несколько идей * использовать replay.js для того, чтобы кэшировать все успешные респонзы. В случае, когда упал внешний сервис, переключаемся на кэш. Только для тестового окружения. * моки для внешнего сервиса для прогона автотестов ### Кэширование + gzip Несмотря на ограниченность канала сотовых сетей, сжатие траффика достаточно для того, чтобы оставлять json-ы максимально читаемыми, не оптимизировать и не урезать данные. Но экономить трафик мобильного приложения - это благородно, особенно, для всяких справочников. Нужно реализовывать Cache-Control, ETag, Expires. iOS и Android поддерживают все из коробки. Соответственно со стороны SOAP понадобятся доработки для возврата дат последнего изменения данных либо информация, насколько часто данные меняются. ### Логирование У нас логируются все xml и json'ы, которые проходят через мобильное API. На проде набегает примерно 5гб в сутки до сжатия, храним неделю. За редким исключением недели вполне достаточно. Приложение на старте генерирует GUID на 20 минут (как бы сессия) и отправляет его в каждый запрос в специальном хедере. Это нужно, чтобы отслеживать поведение пользователя, даже пока он не авторизован или меняет учетку. API в каждом запросе возвращает ResponseTag. Разработчики мобильного приложения могут сообщить его при обнаружении проблем с запросом, чтобы затем было удобнее искать конкретный запрос по логам. ### Версионирование iOS во всех запросах стандартно отдает User-Agent c версией приложения. В Android для этих целей добавили хедер AppVersion. Как вариант, попробовать также пихать в User-Agent. По классике API имеет версию, а клиент указывает, с какой версией хочет работать. У нас, поскольку все потребители заранее известны, проверка версии происходит на стороне API в хедерах User-Agent и AppVersion. Таким образом, если возникает необходимость что-то поправить для старых версий, мы делаем проверку в API с указанием версий приложения. В классическом способе придется записывать в таблице, какая версия приложения на какую версию API смотрит. Поля и методы, которые становятся depreceted, желательно помечать в комментах датой, когда появилась метка, чтобы подчищать API по мере ухода старых версий из маркета. Также иногда возникает необходиость обрезать доступ к некоему методу для старых версий приложения. Мы просто кидаем бизнес-ошибку вида "ваша версия приложения устарела". Как более мягкий вариант, можно было бы в header добавить поле warning_message для того, чтобы выводить данный алерт, но при этом продолжать работу как обычно. ### Отмена операций Наш SOAP-сервис не поддерживает cancellation. Для этой проблемы два решения: * блокировать отмену операции на ui до полного выполнения запроса * обрабатывать отмену в API и дергать второй SOAP-метод, аннигилирующий действие первого метода - мы так сделали ### Окружения API живет в 4х окружениях: * тест - для разработки приложения, здесь самая актуалные изменения * стейдж (демо) - для тестирования и демонстрации заказчику * препрод - это в среде заказчика, смотрит на боевоей сервер * прод На тесте http-кэш полностью выключен, чтобы разработка шла на актуальной версии респонзов. Android сборки: QA - смотрит на API Test, Stage, Preprod - в меню можно менять сервера. В идеальном мире адрес сервера можно вводить вручную, тогда можно тестировать работу со своим локальным инстансом API. Release - смотрит на API Prod iOS: DT - смотрит на API Test DS - смотрит на API Stage DPP - смотрит на API PreProd Release - смотрит на API Prod для iOS проблематично делать переключение серверов, ибо для пушей нужны разные сертификаты