Ошибки
Модель, не знающая формы ошибки, не умеет её обработать — и человек тоже. Поэтому ошибки описаны наравне с успехом, а не в примечании.
Эта страница — одна из трёх в разделе, которые описаны по-настоящему и не изменятся: форма ошибки задана целиком, и реализация её не поменяет.
Код отвечает за результат, тело — за детали #
Никаких 200 OK с {"success": false} внутри. Если запрос не выполнен, это видно
по коду HTTP, а не по разбору тела.
{
"error": {
"type": "validation_error",
"code": "invalid_field",
"message": "Поле email имеет неверный формат",
"field": "email",
"doc_url": "https://docs-school.sersidteh.ru/api/errors/",
"request_id": "req_01HQZXA7M3PK9E"
}
}
| Поле | Что это |
|---|---|
type |
Класс ошибки. По нему ветвится обработчик |
code |
Конкретная ошибка внутри класса |
message |
Текст на языке школы. Для человека, а не для условия в коде |
field |
Поле, вызвавшее ошибку валидации |
doc_url |
Ссылка на объяснение |
request_id |
Идентификатор запроса. Он же в заголовке X-Request-Id |
Ветвиться в коде надо по type и code, а не по message: текст сообщения
переводится и уточняется, коды — нет.
Полный список кодов #
| Код | Когда | Что делать |
|---|---|---|
400 bad_request |
Синтаксис запроса неверен | Чинить запрос. Повтор без правки бессмыслен |
401 unauthorized |
Токен отсутствует, недействителен или отозван | Проверить заголовок и не отозван ли ключ. Повтор бессмыслен |
403 forbidden |
Токену не хватает права | В ответе сказано, какого именно. Выдать право или использовать другой ключ |
404 not_found |
Объекта нет или он вне видимости токена | Различить это снаружи нельзя намеренно: иначе перебором можно узнать, какие объекты существуют |
409 conflict |
Конфликт состояния: заказ уже оплачен, доступ уже выдан | Прочитать текущее состояние объекта и решить. Повтор даст тот же ответ |
422 unprocessable |
Синтаксис верен, бизнес-правило нарушено | Читать code: причина в нём |
429 rate_limited |
Превышен лимит | Ждать столько, сколько сказано в Retry-After, и повторить |
500 internal_error |
Наша ошибка | Повторить позже. request_id обязателен в ответе — с ним и приходить |
503 unavailable |
Плановые работы или перегрузка | Повторить позже, уважая Retry-After, если он есть |
Разница между 400 и 422 стоит того, чтобы её знать. 400 — запрос не разобрался:
не тот тип, сломанный JSON, отсутствует обязательное поле. 422 — разобрался и не
прошёл по правилу: заказ уже отменён, доступ уже отозван, сумма возврата больше
платежа. Первое чинится в коде клиента, второе — решением, что делать дальше.
Ошибок может быть несколько #
Возвращать по одной ошибке валидации и заставлять клиента исправлять их по очереди — плохой тон: за пять полей клиент сделает пять запросов и получит пять отказов.
Поэтому у ошибок валидации в теле массив:
{
"errors": [
{
"type": "validation_error",
"code": "invalid_field",
"message": "Поле email имеет неверный формат",
"field": "email",
"request_id": "req_01HQZXA7M3PK9E"
},
{
"type": "validation_error",
"code": "required",
"message": "Поле first_name обязательно",
"field": "first_name",
"request_id": "req_01HQZXA7M3PK9E"
}
]
}
request_id одинаковый: это один запрос с двумя претензиями к нему.
Идентификатор запроса #
request_id есть в каждом ответе, включая успешные, в заголовке X-Request-Id.
По нему в журнале находится полная трассировка запроса.
Практически: логируйте его на своей стороне рядом с каждым вызовом. Именно это превращает разбор случая «в четверг у клиента не выдался доступ» из гадания в работу — без него остаётся сравнивать время и надеяться.
Что вернётся в четырёх частых случаях #
Прав не хватило. 403, и в ответе сказано, какого права не хватило. Не «доступ
запрещён» вообще, а конкретика: иначе интегратор перебирает права наугад.
Объект удалён. 404. Мягко удалённый объект от несуществующего снаружи
неотличим — и это намеренно.
Превышен лимит. 429 и заголовок Retry-After в секундах. Клиент обязан его
уважать; в наших клиентских библиотеках это встроено. Игнорирование Retry-After
и повтор в цикле — самый быстрый способ получить более жёсткий лимит.
Тело не прошло проверку. 400 или 422 — см. разницу выше, — и, если ошибок
несколько, все сразу.
Обработчик на клиенте #
Минимум, который стоит написать один раз:
# Повторять можно: 429, 500, 503 — с задержкой из Retry-After или с ростом.
# Повторять бессмысленно: 400, 401, 403, 404, 409, 422 — ответ не изменится.
Разделение простое: повторять имеет смысл там, где виноваты нагрузка или мы. Там, где виноват запрос, повтор даст тот же ответ и потратит лимит.