Валидация в Rest контроллере

 
 
 
Сообщения:187
Есть класс сущности:
@Entity
@Table(name = "classes")
public class Group {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@NotNull
	@Pattern(regexp = "^[1]?\\d{1}[А-Я]{1}$")
	private String name;

	@NotNull
	@OneToOne
	@JoinColumn(name = "teacher_id")
	User teacher;

	@OneToMany(fetch = FetchType.EAGER)
	@JoinTable (
	        name="class_students",
	        joinColumns={ @JoinColumn(name="class_id", referencedColumnName="id") },
	        inverseJoinColumns={@JoinColumn(name="student_id", referencedColumnName="id")}
	    )
	private List<User> users;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public User getTeacher() {
		return teacher;
	}

	public void setTeacher(User teacher) {
		this.teacher = teacher;
	}

	public List<User> getUsers() {
		return users;
	}

	public void setUsers(List<User> users) {
		this.users = users;
	}

	public Long getId() {
		return id;
	}
	
	

}


Есть контроллер:
@RestController
@RequestMapping(value = "/classes", produces = "application/json")
public class GroupRestController{
	
	@Autowired
	GroupService groupService;
	
	@GetMapping
	@ResponseBody
	public List<Group> list() {
		return groupService.list();
	}
	
	@PostMapping
	public ResponseEntity<Object> createGroup(@Valid @RequestBody Group group) {
		groupService.save(group);
		return new ResponseEntity<>("Class is created successfully", HttpStatus.CREATED);
	}
		 
}

Когда я делал MVC приложения, то валидация данных отрабатывалась, некорректные данные не вносились в базу. Здесь же все ограничения игнорируются, словно не стоит аннотации @Valid.
Есть ли разница в валидации MVC и Rest? Читаю материалы в интернете - вроде всё делаю правильно.
 
 
Сообщения:9894
С виду выглядит все верно. А bean validation реализация (HibernateValidator?) подключена к проекту?

PS: как правило доменные сущности и то что приходит в контроллер стараются разъединять, создают специальные DTO классы. Они в любом случае в какой-то момент начинают расходиться.
Изменен:15 ноя 2019 06:45
 
 
Сообщения:187
Явно у меня нигде нет этой реализации. Я так понимаю, она где-то в дебрях Spring скрыта. Вот ссылка на весь проект: https://github.com/vall-ball/school01
DTO классы - это ещё один слой? Типа DAO, Service?
 
 
Сообщения:9894
vallball:
Явно у меня нигде нет этой реализации. Я так понимаю, она где-то в дебрях Spring скрыта. Вот ссылка на весь проект: https://github.com/vall-ball/school01
Ну нет :) Подключай Hibernate Validator, он там еще потребует expression language (EL) реализацию для интерполяции (хз кто придумал это слово) сообщений.
vallball:
DTO классы - это ещё один слой? Типа DAO, Service?
DTO относятся к слою Endpoints/Controllers. Но да, это еще один тип классов которые подстраиваются под то что нужно клиенту (а не то что хранится в БД).
 
 
Сообщения:187
Hibernate Validator - его нужно внести в зависимости? Или он явным образом должен появится в коде? Я для MVC его явно не задавал, это точно.
 
 
Сообщения:9894
Он должен в зависимостях появиться.
 
 
Сообщения:187
Староверъ:
Он должен в зависимостях появиться.

Спасибо, это решило проблему.
 
 
Сообщения:888
На мой взгляд, помещать бизнес логику (валидация данных предметной области) в контроллере - сомнительное решение от Spring. Логичнее размещать её на слое сервисов.
 
 
Сообщения:9894
Слой сервисов - это тоже не место для бизнес логики. В целом-то логично валидировать input как только он пришел. Когда в метод приходят параметры - мы их сразу как правило валидируем и бросаем ошибку, дальше пускать выполнение бессмысленно. Здесь та же логика - зачем входить в сервис (потенциально начиная транзакции) если можно сразу же ответить 403 или че там еще.

С другой стороны если используется Hibernate и тот тоже вызывает валидацию, то безопасней это делать на нижнем уровне. Какие-то объекты создаются и заполняются HTTP запросами, но у нас также может быть логика внутри приложения которая создает эти же объекты. Тогда все они будут валидироваться на общем уровне - перед сохранением в БД. Это не производительно, однако и ошибки валидации - не самая частая ситуация.

В общем в обоих подходах есть плюсы и минусы. Я склоняюсь больше к валидации на нижнем уровне потому что наталкивался на ситуации когда невалидные объекты создавались бизнес логикой (по ошибке) и сохранялись в БД, и об этом узнавали только через некоторое время.
Изменен:18 ноя 2019 06:23
 
 
Сообщения:888
Почему-то я всегда считал, что бизнес-логика реализуется на слое сервисов. Вот и Фаулер говорит об этом: https://martinfowler.com/eaaCatalog/serviceLayer.html
Если не там, то где?

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

Итого: задача контроллера - конвертация данных и вызов операции на сервисном слое.
Он может возвращать ошибки конвертации данных (например ввели строку вместо числа) и ошибки с сервисного слоя.
.
Изменен:18 ноя 2019 07:23
 
 
Сообщения:9894
Роман Осипов:
Почему-то я всегда считал, что бизнес-логика реализуется на слое сервисов. Вот и Фаулер говорит об этом: https://martinfowler.com/eaaCatalog/serviceLayer.html
Фаулер (как и Еванс но он называет этот слой Application) предлагают создавать слой сервисов для:
Quote:
A Service Layer defines an application's boundary [Cockburn PloP] and its set of available operations from the perspective of interfacing client layers.
Что касается бизнес логики, то Фаулер описывает два подхода: Transaction Script (бизнес логика находится непосредственно в сервисе) и Domain Model (логика находится в сущностях доменной модели, а сервис является Фасадом - он вызывает ее, но сам непосредственно ничего не делает). На сегодняшний день наверно все сходятся к тому что Domain Model более адекватный подход, особенно когда логики много. Хотя мнения по тому как ее реализовывать разнятся - кто-то считает что даже работу с БД нужно туда помещать.

В целом я согласен что никто не мешает валидацию сделать в Доменной Модели, и при этом вызвать ее из Сервиса. Однако это чревато все теми же проблемами с DRY потому как эти объекты могут создаваться не одним сервисом и уж точно не одним сервисным методом. Единственный способ не нарушать DRY - это (повторюсь) вызывать валидацию уже в репозиториях. Но и свои недостатки у этого есть, поэтому скорей всего в итоге будет какой-то комбинированный подход.

Роман Осипов:
- в Spring при валидации срабатывает магия, отладчик даже не заходит в код контроллера. Магия в бизнес-логике это нехорошо;
Эт да, но в любом случае нужен будет тест который проверяет вызывается ли валидация (в дополнение к тестированию самих правил валидации на уровне Доменной Модели, см. Downsides of anemic model или вот с гейзенбага). Ну и валидация - это одна из простых частей в проекте, эту магию думаю что все понимают.
Изменен:18 ноя 2019 09:54
 
Модераторы:wedens
Сейчас эту тему просматривают:Нет