Pull to refresh

Comments 11

Кроме конроллеров есть еще RouterFunction, более универсально обрабатывать ошибки в фильтрах

У нас в проектах они не используются, поэтому не было смысла переходить на более низкий уровень. Тем не менее, всплывающее исключение имеет всю информацию и может быть обработано аналогичным образом в фильтре

Интересный путь. Все ждал когда будет переход к ProblemDetails но так и не увидел

ProblemDetails, как реализация стандарта RFC 9457, описывает представление ответа в случае ошибки. В рамках данной статьи я пытался сделать упор на подкапотную составляющую. Понятное дело, что имея необходимую информацию об ошибке, можно представить ее в любом удобном виде

Круто.

Как-то все это неправильно. Вместо простого "неправильного" кода получаем совершенно непонятные вещи.

Второй вопрос. Зачем в неправильном коде обертки try-except? Зачем вы их ловите? Чтобы что? Снова возбудить? Достаточно принять все исключения в rest-controllere. В абстрактном классе. Неужели в springе в контроллере не выдает 500 с описанием текста из исключения?

Любая бизнес-логика сопровождается проверками, как входными, так и по ходу действия, и если что-то не так, возбуждается исключение с вменяемым сообщением. Все просто. Зачем эти нагромождения try-except?

В нашем случае любая ошибка должна считаться ошибкой бизнес-логики и должна сопровождаться двумя сообщениями: 1 - техническое, оригинальный текст сообщения, 2 - бизнес ошибка, какая операция не может быть выполнена и почему (этот же текст мы должны показать пользователю на фронте)

При такой постановке задачи, мы пытались вначале поймать и обернуть ошибки как можно ближе к месту возникновения, а затем стали дообогащать оригинальные исключения кодом ошибки (и текстом, соответствующим этому коду)

Если просто перехватывать ошибки на уровне контроллера, то, например, RestClientException нам не скажет ничего о системе, к которой мы пытались обратиться с помощью http-клиента и бизнес-операции, которую пытались выполнить

Кажется, я не совсем понял возможно ли в данном подходе отдавать разные коды ошибок внутри одного метода и как? В методе, например, может быть ошибка что, юзер не найден или подписка не найдена, аккаунт заблокирован или юзер заблокирован и т.д. К сожалению, в реальном мире почти невозможно плодить микрометоды под каждую ошибку отдельно или походы в другие микросервисы могут порождать разные ошибки.

Если коротко, то да. Ведь суть подхода сводится к тому, чтобы в случае ошибки дообогатить ее исключением, содержащим код ошибки. Варианты как это сделать:

  1. Как вы правильно отметили, можно декомпозировать операцию авторизации на методы и переложить работу на аспекты

  2. Можно использовать классический подход и выкидывать "свои" UserNotFoundException, а уже в @ControllerAdviceприсваивать этим ошибкам код (и текст)

  3. Можно написать обработчик try-catch с добавлением Exception с кодом ошибки в suppressed вручную, например через статик метод.

У нас есть очень небольшой процент таких кейсов, и как-правило мы идем по 1 или 2 пути

Я понял. Возможно у вас действительно очень специфичный кейс когда достаточно одной ошибки. Но у нас в реальной жизни в проекте мы выбрали как раз путь вложенных классов (на котлине очень просто и круто реализуется) и в exception handler’e прописали 1 корневой ApiExeption, в котором логика запаковки в json для ответа. Теперь не нужно больше ничего туда добавлять. А в коде вместо IllegalException и прочих кидаем свои с необходимым именем. Это дает возможность в методе кидать столько разных ошибок, сколько нужно и главное, что в коде по имени исключения понятно за что оно отвечает. Ну и на скорость не сильно влияет, нет лишних аспектов на каждом вызове. А чтобы не плодить коды и исключения - организовали их в группы. Очень читабельный код получается. Ну и поверх класса с кодами добавили генерацию html доки для саппорта и тестировщиков с описанием.

Мы долго шли по этому пути (как я попытался описать в статье), и до какого-то момента нас это тоже устраивало. Но самыми значимыми минусами стало:

  1. Java класс содержащий коды ошибок. Он был в общей либе для всех сервисов, т.е при добавлении нового кода ошибки, надо было эту библиотеку менять

  2. Нужно не забывать везде блоки try-catch

  3. Помимо ApiException нужно еще и корневой Exception описать, потому что где-нибудь про блок try-catch забудешь

  4. Лишняя логика по обработке и лишняя логика в тестах

  5. Самое главное - от нас бизнес стал требовать разную логику по формированию сообщений в случае разных типов ошибок. Поэтому появились instanceOf в коде

Понятно, что все очень сильно зависит от проекта и требований, и никакого идеального решения не будет никогда.

А вот про ставить везде try/catch не понял - зачем это делать если кастомный ApiException наследуется от RuntimeException и в коде никак особо не выделяется, поэтому нет необходимости его везде специально ловить. А корневой exception также описывается в exception handler с общей ошибкой и своим кодом и опять же нигде не нужно его ловить специально или помнить, если только мы не пишем что-то отличное от rest service, но такого в реальной жизни процентов 5, наверное.

Sign up to leave a comment.