1. Web 요청 모델과 Service 요청 모델을 분리했는가?

  • spring-boot-starter-validation이 표현 계층 하위에서 필요한지 생각해 보기(domain이나 application...등등에서 불필요함!)
data class ReserveProductWebRequest(
    ....
) {

    fun mapToServiceRequest(): ReserveProductRequest {
        return ReserveProductRequest(
            shopId,
            products.map { it.mapToServiceObject() },
            LocalDateTime.parse(reservedAt)
        )
    }
}

 

2. 중첩해서 검증하고 싶다면?

  • 중첩 DTO의 예시는 다음과 같음
    • ReserveProductWebRequest(검증 대상)
      • shopId: Long
      • products: List<ReservedWebProduct> (중첩 검증 대상, 이곳에 @Valid 붙일 것)
        • productId: Long
        • ...중략
      • reservedAt: String

 

3. Handler에 @RestControllerAdvice가 걸려 있는가?

  • JSON으로 예외 응답을 내려주고 싶은 경우에는 @ControllerAdvice가 아닌, @RestControllerAdvice 사용
  • 대신 응답을 커스텀으로 내려주는 경우에(ResponseEntity 미사용) @ResponseStatus를 사용할 것

 

4. data class를 요청 dto로 사용하는 경우

data class ReserveProductWebRequest(
    @field:NotNull(message = "예약 대상 가게 식별자는 필수입니다.")
    val shopId: Long?,

    @field:Valid
    @field:NotNull(message = "예약 상품 목록은 필수입니다.")
    val products: List<ReservedWebProduct>?,

    @field:DateValid
    @field:NotNull(message = "예약 시간은 필수입니다.")
    val reservedAt: String?
) {

    fun mapToServiceRequest(): ReserveProductRequest {
        return ReserveProductRequest(
            shopId!!,
            products!!.map { it.mapToServiceObject() },
            LocalDateTime.parse(reservedAt!!)
        )
    }
}
  • validation 기능 이용하고 싶다면, 위와 같이 null 가능 타입으로 선언하고, 사용할 때는 단언
  • null이 가능하지 않은 타입 사용할 경우, HttpMeesageNotReadableException 발생 가능함
  • 위의 경우에는 무엇 때문에 예외가 발생하는지 클라이언트에서 알기 어려움
  • @field:NotNull 처럼 @field는 data class를 사용하는 경우에만 사용함
  • 기본 class에서는 @NotNull만 사용해도 동작함. 단, 코틀린 1.6.10 버전부터는 해당 이슈가 해결된 것으로 보임!
이하눌