Как донести понятные ошибки до клиента
Что проверяют
Понимаете ли вы, что ошибка это часть интерфейса API, а не отладочный вывод. Вопрос про проектирование ответов, а не про переписку с заказчиком.
Как отвечать
Ошибка должна отвечать на три вопроса: что произошло, кто виноват (клиент или сервер) и что делать дальше.
Из чего складывается хороший ответ об ошибке:
- правильный код состояния: 400 при неверном запросе, 401 при отсутствующей аутентификации, 403 при нехватке прав, 404 когда объекта нет, 409 при конфликте, 422 при семантически неверных данных, 429 при превышении лимита, 5xx только когда виноват сервер. Возвращать 200 с ошибкой в теле нельзя;
- машиночитаемый код (
ORDER_ALREADY_PAID), по которому клиент строит логику. Разбирать текст сообщения регулярками клиент не должен; - человекочитаемое сообщение на языке пользователя, без имён классов и стектрейсов;
- привязка к полю при ошибках проверки: список из имени поля и причины, чтобы форма подсветила конкретный ввод;
- идентификатор запроса в теле и заголовке, чтобы поддержка нашла случай в логах;
- единый формат для всех ручек, например по стандарту описания проблем (RFC 7807 с полями
type,title,detail).
В реализации это @ControllerAdvice с обработчиками исключений, единый класс ответа и правило: наружу не уходит ничего внутреннего, ни SQL, ни стектрейс, ни имя таблицы. Подробности пишутся в лог, клиенту достаётся код и идентификатор.
Где спотыкаются
Отдают клиенту текст исключения целиком, раскрывая устройство системы.
Используют один код 400 на все случаи, и клиент не может отличить «поле пустое» от «денег не хватает».
Пишут только текст без машинного кода, и локализация с обработкой на клиенте становятся невозможными.