
Привет, Хабр! Меня зовут Екатерина Саяпина, я Product Owner платформы МТС Exolve. Коды ошибок — последнее, что хочет видеть разработчик в ответе API. И означают они одно из двух: либо есть проблема в запросе, либо что-то сломалось на стороне API.
В любом случае трафик останавливается: нужно найти причины и решения. И коды ошибок в этом случае — полезный диагностический элемент. Сегодня я расскажу про подходы к их обработке и дам пример распространенной классификации.
Коды ошибок: значение
Коды ошибок при ответе API — основной способ, с помощью которого разработчик может сообщить пользователю о проблеме. Они следуют за начальным запросом и представляют собой прямую связь между клиентом и API.
Часто этот шаг не только информирует о сбое, но и помогает запустить процесс отладки. Коды одновременно проясняют ситуацию и уведомляют о предполагаемой неисправности.
Рассмотрим, например, код 401 Unauthorized — Please Pass Token. Здесь очевидна суть сбоя: пользователь не прошел аутентификацию. По нему сразу понятна предполагаемая неисправность — API требует токен, и для предоставления доступа он должен быть передан как часть запроса.
Коды состояния HTTP

Их можно встретить не только при работе с API, но и при обычном просмотре web-страниц. Их можно разделить по группам значений.
1XX — информирование
У диапазона кодов 1XX есть две основные функции. Первая заключается в передаче информации о состоянии протокола подключенных устройств. Например, 101 Switching Protocols — это код, отмечающий, что запрос клиента на изменение протокола с сервера был одобрен. Диапазон 1XX также уточняет состояние первоначального запроса. Код 100 Continue означает, что сервер, получивший от клиента заголовки запроса, ожидает его тело.
2XX — успех
Коды 2XX отмечают ряд удачно завершенных действий и объединяют ответы в определенные коды. Первые три прекрасно демонстрируют этот диапазон:
200 OK — запрос прошел успешно.
201 Created — запрос выполнен, и создан новый ресурс для клиента.
202 Accepted — запрос принят, и обработка началась.
3XX — перенаправление
Коды 3XX полностью соответствуют статусу ресурса или конечной точки и показывают, что для успешного завершения операции нужно выполнить другой запрос, чаще всего по иному URL.
К примеру, 301 Moved Permanently проверяет, действительно ли запрос клиента достиг правильной системы, а также то, что этот запрос и все будущие должны обрабатываться другим URl. Это очень полезно в субдоменах и при перемещении ресурса между серверами.
4XX — ошибка клиента

Серия 4XX самая знаменитая — 404 Not Found показывает неправильно сформированные URL-адреса, и URI и является одним из популярных мемов. Однако в этом диапазоне существуют и другие полезные коды для API.
414 URI Too Long — общий код состояния. Он обозначает, что данные, передаваемые методом GET, слишком длинные и должны быть преобразованы в POST. Также можно укоротить URL-запрос вручную или изменить его структуру.
Другой распространенный код — 429 Too many Requests — используется для реализации механизмов ограничения частоты запросов (rate limiting), чтобы показать попытки клиента одновременно выполнить слишком много запросов. Также может указывать на DDoS-атаку.
5XX — ошибка сервера
Диапазон 5XX зарезервирован для кодов, специально связанных с функциональными возможностями сервера. Например, 502 Bad Gateway означает, что вышестоящий сервер вышел из строя и текущий является шлюзом. Также он дополнительно раскрывает место возникновения сбоя. Есть и менее конкретные коды, указывающие на общие неполадки, например 503 Service Unavailable — сервис недоступен.
Как работать с кодами ошибок
Когда у нас есть четкое представление о кодах состояния HTTP, мы можем проанализировать, какие из них сообщают не только о проблемах, но и о причинах.
Непрозрачные коды ошибок бесполезны. Представим, что вы пытаетесь отправить запрос GET к API, который обрабатывает инвентарь цифровой музыки. Вы передаете данные в API, регулярно принимающий ваш трафик, отправляете правильные учетные данные для авторизации и аутентификации и ждете ответ сервера.
Вместо него вам прилетает 400 Bad Request без дополнительных данных. Этот код находится в диапазоне 4XX и показывает, что проблема была на стороне клиента. Подробностей в нем нет — только скудные сведения о «некорректном запросе». Этот пример иллюстрирует случай, когда код ошибки не несет практической пользы.
Хорошие сообщения об ошибках должны включать:
Код состояния HTTP, позволяющий легко определить источник и область проблемы.
Идентификатор внутренней ссылки для обозначения ошибок, специфичных для документации. В некоторых случаях он может дополнить HTTP-код, предоставляя ссылку на конкретную страницу, где эта проблема описывается подробно.
Сообщение с контекстом, причиной и общим решением возникшей ошибки.
В примере выше 400 Bad Request ничего не означает, хотя код должен давать дополнительный контекст. Один из способов добавить его — передать информацию в теле ответа на языке, общем для самого запроса.
Например, код ошибки 400 Bad Request может легко форматировать в JSON с полезной для клиента информацией:

Конкретный тип сбоя показывает, с чего пользователю начать решение проблемы. Кроме того, он дает внутренний идентификатор ссылки (BR0x0071), по которому ошибку можно найти в документации.
Читабельность
BR0x0071 — это машиночитаемый ссылочный код к примечанию о внутренней ошибке, но пользователю он до сих пор не понятен. Чтобы разобраться в проблеме, ему придется закопаться в документацию. Хорошей практикой в проектировании API является отделение кода ошибки от текстового сообщения.
Это помогает:
Четко различать машинно ориентированные коды ошибок и текстовые пояснения для человека.
Упростить обработку ошибок на стороне клиента. Так разработчики могут использовать error_code для программной обработки, а error_message — для информирования пользователя.
Исправим это и внесем изменения, сохраняя ссылочный номер:

Теперь по ответу понятно, что проблема спряталась в параметрах, и он может приступить к устранению неполадок.
Примеры
Давайте посмотрим коды ошибок в некоторых популярных системах.
Twitter API — отличный пример реализации развернутых сообщений об ошибках. Отправим запрос GET, чтобы получить временную шкалу упоминаний:
GET https://api.twitter.com/1.1/statuses/mentions_timeline.json
Нам возвращается такой ответ:

Переданный пользователю код ошибки — 400 Bad Request. Он указывает, что проблема в запросе. Длина нашего контента приемлема, а время ответа находится в пределах нормы. Однако мы видим уникальный код 215 прикрепленным сообщением «неправильные данные аутентификации».
Bing
Чтобы показать сложный код ответа на ошибку, отправим плохо сформированный (по сути нулевой) запрос GET в Bing:

Bing возвращает нам код 1001 вместе с сообщением о том, что параметр отсутствует. Он обозначается как SearchRequestAppId, а переменная HelpUrl передается как ссылка на решение.
В этом случае у нас есть машиночитаемый код ошибки, понятное описание проблемы и ссылка на документацию по ней.
О важности баланса
Как мы видим из примеров, у большей части кодов ошибки нет строгой структуры, и вы сами можете выбирать, на что ссылаться, какие данные выводить и как их отображать. Но общая цель подобных ответов — не только информировать пользователя, но и помогать ему. То же относится и к сбоям API.
Важно добиться баланса — информативности и краткости. Развернутое описание проблемы и данные для ее решения должны сочетаться с легкостью чтения и анализа.