---
# System prepended metadata

title: Mobile API

---

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 проблематично делать переключение серверов, ибо для пушей нужны разные сертификаты 



