Анонс: классификатор кода ошибок и работа с дубликатами

После долгой паузы и анализа обратной связи, мы доработали некоторые части системы и рассказываем о предстоящих изменениях.

Классификатор кода ошибок

За все время существования наших сервисов одним из главных замечаний партнеров было то, что при интеграции нашего API им трудно обрабатывать ошибки, потому что большей частью они описаны произвольно, а в ‘выковыривании’ причин из текстового сообщения приятного мало.

В ближайшее время мы выпустим обновление, в котором в ответ с ошибкой будет дополнительно передаваться причина в виде цифрового кода ошибки по общему классификатору. Весь список можно посмотреть в документации API, но давайте рассмотрим пример ответа при создании выплаты, когда на кошельке нет баланса.

Раньше результат был примерно такой:

{
"error": {
"code": 400,
"request": "b6dcb689-cd7d-91f8-a27c-4d35b2053274",
"message":"Insufficient funds on the contract ID, cannot transfer `5000`, only `2000` available"
}
}

Как видно из примера, единственный вариант понять, что причина именно в балансе - это проверять текст в сообщении. Однако текст является скорее общим описанием проблемы, чтобы клиент смог быстро понять причину. Так как в нашем случае клиенты - это системы наших партнеров, ошибки должны иметь структуру и быть машиночитаемы.

После выпуска обновлений системы сообщение об ошибке в случае недостаточности баланса будет выглядеть вот так:

{
"error": {
"code": 400,
"reason": "200201",
"request": "b6dcb689-cd7d-91f8-a27c-4d35b2053274",
"message":"Insufficient balance",
"details": {
"amount": "10000",
"balance": "1000"
}
}
}

Теперь у нас есть код ошибки в `reason`, а также дополнительно `details` с деталями ошибки.

Защита от дубликатов

Подробнее об этом можно прочитать в соответствующем разделе документации.

Рассмотрим случай, когда в системе срабатывала защита от дубликатов, но клиенту это доносилось в неудобном виде:

Клиент отправляет запрос на создание новой заявки к выплате

Заявка создается, но корректный ответ не доносится по причине технической ошибки с сетью, нашим сервером или сервером клиента. Это техника, такое бывает. Для таких случаев клиент передает внешний идентификатор в поле `external_ref_id`, чтобы в случае проблем отправить запрос повторно

Из-за проблемы с отправкой заявки клиент отправляет тот же запрос повторно. Но тут возникает проблема с обработкой запроса уже на нашей стороне

Если в системе уже была заявка с тем же внешним идентификатором, в ответ выдавался следующий ответ:

{
"error": {
"code": 400,
"request": "e6ba3aad-7954-9534-a292-18f2e61d50b4",
"message": "Invalid form request, see `data` for details",
"data": {
"external_ref_id": "Value should be unique."
}
}
}

На первый взгляд вроде бы все ясно, но интеграционный код клиента уже покрыт слоем сложности - факт дубликата выражен не самым тривиальным образом и фактически требует детального разбора всего ответа.

Мы вернулись сразу с двумя вариантами решения этой проблемы:

Вариант 1. Ничего не меняется, но код ошибки дубликата выглядит несколько иначе:

{
"error": {
"code": 400,
"reason": "100100",
"request": "e6ba3aad-7954-9534-a292-18f2e61d50b4",
"message": "Duplicate request attempt",
"details": {
"id": 123,
"external_ref_id": "376716985183021"
}
}
}

Теперь у нас есть не только явно переданный сигнал о дубликате в поле `reason`, но и вспомогательная информация в `details`. Больше не нужно пользоваться поиском и искать исходную заявку, она уже передана.

Вариант 2. Данный подход мы рекомендуем для всех новых интеграций.

Достаточно будет просто передать вместе с запросом заголовок `Idempotency-Replay: true`, и вместо ответа с ошибкой система вернет исходную заявку, как если бы никакого дубликата и не было. (при этом в ответе будет заголовок `Idempotency-Replayed: true`; то есть заявку вернули, но если кому-то важно, дали знать, что это был replay операции)

Оба варианта подразумевают, что клиент получает запрос от своего пользователя в браузере или приложении, создает заявку в своей системе, а затем пытается передать ее нам с внешним идентификатором уже асинхронно через очередь задач.

Все изменения пока отлаживаются в тестовой среде и будут выпущены в течение недели. Напишите нам, если у вас есть какие-то замечания или предложения.