Привет, Хабр! Меня зовут Екатерина Саяпина, я 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.
Важно добиться баланса — информативности и краткости. Развернутое описание проблемы и данные для ее решения должны сочетаться с легкостью чтения и анализа.
Комментарии (6)
savostin
05.02.2025 07:49Холивара ради: должен ли API всегда при ошибке возвращать http status != 200/302 или как в примере возвращать всегда 200, а в теле сообщать о проблемах?
space2pacman
05.02.2025 07:49Кому как удобно
Кто-то API делает с учетом кодов и типов запроса
Кто-то работает только с 200-ым кодом но с разными типами запросов
А кто-то вообще только на POST запросах проектирует API
big17
05.02.2025 07:49Как будто бы не совсем точный заголовок статьи. Ожидание, что там будет описано как фронтенд обрабатывает ошибки от REST API
mitix
Удивлен, что не упомянули Problem Details
dab1818
...и более "свежий" Problem Details https://www.rfc-editor.org/rfc/rfc9457.html