SP
1. апи эндпоинт, принимает какие-то данные
2. внутренняя логика, которая эти данные как-то генерирует
У нас есть ДТО (для АПИ = контракт), которая создается по определенным правилам (типы, required поля и т.д.)
Во время создания ДТО мы можем развалиться.
Если мы хотим исчерпывающий отчет по ошибки для случая 1 - валидируем входные данные на момент соблюдения контракта до создания ДТО
Если человек по каким-то причинам создает невалидную ДТО в рамках внутренней логики - он получит ошибку процесса маппинга на ДТО, захочет - обработает
Дальше у нас идут правила, которые должны быть соблюдены для корректной работы метода службы. Их можно делать как через VO, возможно можно делать их через
validate->(DTO)
на входе и т.д.Как итог: обьект (инстанс службы) через свой метод (проверки вызываемые в нем) должен проверять правила требуемые для конкретного юз кейса. Таким образом, как по мне, дубликация правил валидации на обоих слоях будет сведена к минимуму и риск некорректной работы сервиса тоже.
Шо скажемс?
Валидация "email не должен быть пустой" - это валидация входных данных и должна она происходить на "входе". До того как ты эти данные успеешь замэпить на что-то и т.д. Можно мэпить на DTO и валидировать если у тебя мэппинг 1:1 - иначе потом сложно понять где проблема.
В целом валидация входных данных нужна "для клиента" и тут сложность для большинства разработчиков в том что они не воспринимают код который дергает из контроллера сервис скажем как "клиент сервиса". для них клиент это мобилка или React апа там где-то.
На каждом уровне есть клиентский код который чет вызываает и на каждом уровне свои правила. + есть разница между "валидацией данных" и "проверкой инвариантов стэйта".
Словом... вся проблема в излишнем обобщении