Ловили когда-нибудь ошибку 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 : Сервер отвечает, что такой запрос не будет обработан.

Клиент отправил некорректный запрос, или сделал это недопустимым способом.

Примеры возможных причин:

  1. Сервер не знает как обработать этот запрос.

  2. Сервер не понял, что хотел сделать клиент.

  3. Нехватает вводных данных, например не указаны обязательные поля.

  4. Данные некорректны, допустим неправильный тип параметра или значение не попадает в нужный диапазон.

  5. Ресурс не найден — 404.

  6. Пользователь должен быть авторизован для выполнения запроса, а пытается выполнить без авторизации — 401.

  7. Пользователю запрещено производить это действие, например он авторизован но ему ему не выдали доступ на указанный ресурс — 403.


5xx : Ошибка на сервере

Примеры возможных причин:

  1. Нет ответа от сервиса, лежащего “за” веб-сервером, например “упал” сервис PHP-FPM — 502

  2. Сервер пытался выполнить запрос, но код вылетел с ошибкой (Exception) — 500

В хорошем API, ошибка 5xx будет отдана в двух случаях — либо сбой инфраструктуры (502), либо запрос невозможно выполнить из-за ошибки в коде (500).

Если вины программиста или инфраструктуры нет, мы возвращаем 4xx.

Правило 2. По возможности указываем причину.

Если мы знаем дополнительную информацию по ошибке и она не секретная — хорошо бы сообщить об этом в ответе, а не просто вернуть код 400 или 500.

Это сильно облегчит задачу любому, кто будет интегрироваться с вашим API.

Плохо:

400 Bad Request

Хорошо:

400 Missing required field "accountId"

Что в итоге

Если коды ответов в нашем API систематизированы, то это существенно помогает в работе.

  • При тестировании API мы сразу можем определить результат по коду HTTP, не изучая тело ответа.

  • При отладке мы сразу определяем какой именно запрос вызывает ошибку.

  • В мониторинге мы можем очень легко настроить отслеживание кодов 500, чтобы сразу узнавать о сбоях нашего кода.