@Override

유효성 검사 dto, entity, controller ,service 어디서...? 본문

백엔드

유효성 검사 dto, entity, controller ,service 어디서...?

치키챠 2022. 3. 24. 23:15

제 생각부터 말하자면 전부 하는게 좋은 것 같습니다.

기존에는 비즈니스 로직에서는 정상값이 간다고 가정하고 비즈니스 코드에만 집중하는게 좋지 않을까? 라고 생각하고

아래 사진 처럼 컨트롤러에서 @Valid를 통해 dto수준에서 웬만한 유효성 검사를 끝내자 라는 생각이었습니다.

비즈니스로직에만 집중할 수 있어서 나름 괜찮다고 생각하고 있었는데, PR에 팀원이 의견을 남겨주었습니다.

 

이런 방식으로는 생각을 못해봤는데, 팀원이 부트캠프도 했었고 다른 사람들의 방식들도 궁금해서 오늘도 역시 스택오버플로우에 검색을 해보았습니다.

 

java - Spring Rest API validation should be in DTO or in entity? - Stack Overflow

 

Spring Rest API validation should be in DTO or in entity?

In which tier should the validation be in a Spring Boot Rest API. I have some models, endpoints and DTOs. I added some @NotNull and @Size annotations in the DTO. I added the @Valid annotation in the

stackoverflow.com

Spring DTO validation in Service or Controller? - Stack Overflow

 

Spring DTO validation in Service or Controller?

I'm building a straight forward AJAX / JSON web service with Spring. The common data flow is: some DTO from browser v Spring @Controller method v Spring @Service me...

stackoverflow.com

spring boot - Should I validate dtos or entities? - Software Engineering Stack Exchange

 

Should I validate dtos or entities?

I want to place validation in one layer for the reason of simple code maintenance. I was thinking of entity validation, cause this protects directly database. Am I right, or should I add validation...

softwareengineering.stackexchange.com

거의 모든 사람이 dto와 entity 혹은 controller와 service 둘 다 유효성 검사하는 것을 추천합니다.

그 이유를 간단하게 요약하자면 첫째는 ""컨트롤러에서 서비스로 정상값이 전달 될 것이다." 라는 가정으로 코드를 작성하는 것은 좋지 않다." 라는 것이고, 둘째는 "협업할때 다른 프로그래머 혹은 본인이 실수 할 수 있고 각 레이어는 유효성검사의 책임을 갖는 다는 것이었습니다."

 

이유들을 듣고 나니 동의 합니다.

서비스입장에서 컨트롤러부터 정상값이 올 것이다. 라고 정하는 것이 암묵적으로 의존성을 갖게 되는 것 같고, 추후에 다른 컨트롤러에서 새로운 방식으로 이 서비스메서드를 쓰는 경우도 있을 것이고, 저는 서비스 메서드에 정상값이 가도록 구현하겠지만 다른 사람들은 실수을 할 가능성도 높구요... 유닛테스의 경우에도 마찬가지 입니다. 서비스메서드에서 유효성검사를 하지 않고 dto에서만 유효성 체크를 할 시에는 처음 구상한것과 다른 값이 db에 들어갈 수도 있습니다.

이 사진은 팀원이 짠 코드입니다. 저는 가입할때 컨트롤러에서 이메일형식인지, 비밀번호 강도를 만족했는지 등을 체크하고 정상값을 서비스에 보내도록 구현했는데, 팀원은 제가 구현한 방식을 잘 몰랐고 서비스 혹은 엔티티에서 유효성 체크하지 않다보니 잘못된 방법도 db에 들어가는 문제가 생겼습니다.

 

그래서 모든 레이어에서 유효성검사의 책임을 갖도록 수정했습니다.

하나의 방식으로 통일하는 것이 좋을 것 같아서 validation 어노테이션 방식으로 entity를 수정

(비밀번호는 encode돼서 들어가기 때문에 정규표현식을 사용하기 어려워서 메서드내에서 따로 검사 했습니다.)

각 클래스 마다 구현하는것은 클래스의 책임을 늘리기때문에 따로 util클래스로 구현했습니다.

이런 식으로 validaUtil.validate()를 사용해서 서비스레이어에서도 유효성 검사를 합니다.

RuntimeException 발생시 스프링 트랜잭션은 기본적으로 rollback을 하므로 바뀐 값들이 반영되지 않습니다.

checked Exception 타입으로 바꾸면 예외가 발생해도 커밋이 되기때문에 롤백전략을 수정해주어야 합니다.

상황에 맞게 롤백전략을 짜시면 될 것 같습니다. (런타임예외가 발생해도 롤백하지 않고 커밋하게 수정가능합니다. 롤백되는건 스프링 기본롤백전략)

 

 

 

참조:

Spring Validation in the Service Layer | Baeldung

 

Comments