Pull to refresh
1
0
Send message

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Как правило, в систему должен приходить уже авторизованный запрос, а за саму авторизацию отвечает отдельный микросервис, гейтвей или даже целая система. Да и видов авторизации пользователей может быть одновременно несколько: логин/пароль, jwt-токен, ldap, сертификат, двухфакторка и т.д.

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

Библиотеки с интерфейсами и моделями (api) каждого микросервиса у нас как раз публикуется в приватном репозитории, и используется в других микросервисах для построения клиентов. При этом мы всегда можем знать, к какому микросервису относится модель и где она используется

Я вижу в создании таких клиентов одну большую проблему - огромное количество типового, шаблонного кода, который приходится писать вручную. И тут нужно либо смириться, либо написать библиотеку с оберткой для клиентов (и описанием исключений возможно), либо переходить на генерацию клиентов по swagger. Помимо этого, удобно использовать аннотации spring boot 3 для создания клиентов на основе интерфейсов

Модуль client это реализация API, которая вызывает сервисный код, или уже готовый клиент к микросервису?

Мы пытались делать REST-клиент, как стартер, поставляемый с микросервисом, но позже отказались от этой идеи. Версии спринга могут различаться, усложняется миграция на новую версию. Поэтому пришли к выводу, что нужно поставлять только интерфейсы для создания и клиента, и серверного АПИ для реализации

Information

Rating
Does not participate
Registered
Activity

Specialization

Backend Developer
SQL
PostgreSQL
Java
Docker
CI/CD