Ловили когда-нибудь ошибку 500
в ответе HTTP API, когда ожидаете 404
или 401
?
Бывало так, что сервер отвечает кодом 200
на любой запрос, в том числе ошибочный?
Знакомо чувство, что для того, чтобы понять почему запрос не отработал, придётся заглянуть в логи сервера, или заниматься экспериментами?
А если это не наше API и доступов к логам и коду нет? Тогда нас скорее всего ожидают трудные времена.
Подумаем, как можно спроектировать своё API так, чтобы к нему было легко подключаться.
Коды статусов HTTP
Коды статусов ответа HTTP группируются так:
1xx : Информационные запросы
2xx : Успешные запросы
3xx : Редиректы (перенаправления)
4xx : Ошибки клиента
5xx : Ошибки сервера
1xx
— ошибки 100 - 199, 2xx
— ошибки 200 - 299 и т.д.
Как выбрать код ответа?
Тот кто отправляет запрос на наш сервер, хочет получить как можно более осмысленный ответ.
Но чтобы дать такой ответ, сначала нужно самим определиться, в каких случаях мы даём одни коды, в каких другие.
Больше всего сомнений возникает, какую ошибку выбросить, 4xx
или 5xx
?
В чем разница между “ошибкой клиента” и “ошибкой сервера”?
Ошибка валидации — это ошибка на клиенте или на сервере?
Попытавшись ответить на эти вопросы, я вывел для себя два правила. Я стараюсь придерживаться этих правил в любом проекте.
Правило 1. Разделяем ошибки клиента и сервера, конкретизируем их.
2xx : Только успешные запросы.
Если запрос не может быть обработан, то в зависимости от причины возвращаем либо 4xx
, либо 5xx
.
Ошибки с кодом 2xx
быть не может, этот код только для успешного выполненного запроса.
4xx : Сервер отвечает, что такой запрос не будет обработан.
Клиент отправил некорректный запрос, или сделал это недопустимым способом.
Примеры возможных причин:
-
Сервер не знает как обработать этот запрос.
-
Сервер не понял, что хотел сделать клиент.
-
Нехватает вводных данных, например не указаны обязательные поля.
-
Данные некорректны, допустим неправильный тип параметра или значение не попадает в нужный диапазон.
-
Ресурс не найден —
404
. -
Пользователь должен быть авторизован для выполнения запроса, а пытается выполнить без авторизации —
401
. -
Пользователю запрещено производить это действие, например он авторизован но ему ему не выдали доступ на указанный ресурс —
403
.
5xx : Ошибка на сервере
Примеры возможных причин:
-
Нет ответа от сервиса, лежащего “за” веб-сервером, например “упал” сервис PHP-FPM —
502
-
Сервер пытался выполнить запрос, но код вылетел с ошибкой (Exception) —
500
В хорошем API, ошибка 5xx
будет отдана в двух случаях — либо сбой инфраструктуры (502
), либо запрос невозможно выполнить из-за ошибки в коде (500
).
Если вины программиста или инфраструктуры нет, мы возвращаем 4xx
.
Правило 2. По возможности указываем причину.
Если мы знаем дополнительную информацию по ошибке и она не секретная — хорошо бы сообщить об этом в ответе, а не просто вернуть код 400
или 500
.
Это сильно облегчит задачу любому, кто будет интегрироваться с вашим API.
Плохо:
400 Bad Request
Хорошо:
400 Missing required field "accountId"
Что в итоге
Если коды ответов в нашем API систематизированы, то это существенно помогает в работе.
-
При тестировании API мы сразу можем определить результат по коду HTTP, не изучая тело ответа.
-
При отладке мы сразу определяем какой именно запрос вызывает ошибку.
-
В мониторинге мы можем очень легко настроить отслеживание кодов
500
, чтобы сразу узнавать о сбоях нашего кода.