Bactoria 황준오

javax.Validation으로 request 검증하기

2019-01-22
bactoria

API를 구현할 때, post 메소드로 body에 데이터를 받는다.

이 때 값들이 유효한 값인지를 검증하여 유효하지 않으면 bad request를 보낼 수가 있다.

간단하고 유용하게 사용할 수 있는 것이 javax.validation.constraints에 있는 애노테이션들이다.

spring-boot-starter-web 의존성을 추가할 경우에는 딸려 들어온다.

image

 

1,2,3의 값 만을 받아야 하는 priority 필드가 있다고 하면

이 때 아래처럼 사용하면 됨.

UpdateTodoRequestDto.class

@NoArgsConstructor
@Getter
public class UpdateTodoRequestDto {
    @NotNull(message = "우선순위를 입력해주세요.")
    @Min(value = 1, message = "우선순위는 1~3 사이의 값이어야 합니다.")
    @Max(value = 3, message = "우선순위는 1~3 사이의 값이어야 합니다.")
    private Long priority;

    //...
}

   

TodoController.class

@Slf4j
@CrossOrigin
@RestController
@RequestMapping(value = "/api/todos", produces = "application/hal+json")
public class TodoController {
    
    @PutMapping("/{id}")
    public int updateTodo(@PathVariable Long id, @Valid @RequestBody UpdateTodoRequestDto dto) {
        log.info("PUT :: /api/todos/" + id + "   dto :: " + dto);
        return todoService.updateTodoWithTitleAndContentAndClosingDateAndPriority(id, dto);
    }
    ...
}

Controller에서 dto 앞에 @Valid 를 추가 해주어야 적용 됨.

   

request image

 

response image

   

가공하기

위의 response처럼 모든 데이터를 응답하지 않고 특정 필드만 응답할 수 있다.

예를들어, message와 field만을 전송하고 싶다면 다음과 같이 예외처리를 해주면 된다.

@ControllerAdvice // 빈등록
public class GlobalExceptionHandler {

    @ExceptionHandler
    public ResponseEntity<String> notValidException(MethodArgumentNotValidException e) {

        ErrorDetails errorDetails = new ErrorDetails(
            e.getBindingResult().getFieldError().getField(), 
            e.getBindingResult().getFieldError().getDefaultMessage());

        return new ResponseEntity(errorDetails, HttpStatus.BAD_REQUEST);
    }

    @Getter
    private class ErrorDetails {

        private String field;
        private String message;

        public ErrorDetails(String field, String message) {
            this.field = field;
            this.message = message;
        }

        @Override
        public String toString() {
            return "ErrorDetails{" +
                    "errorField='" + field + '\'' +
                    ", message='" + message + '\'' +
                    '}';
        }
    }

}

 

request image

 

response image

간결해졌다.

   

테스트

TodoControllerTest.class

@RunWith(SpringRunner.class)
@WebMvcTest(TodoController.class)
public class TodoControllerTest {
    @Test
    public void 우선순위가_4인_Todo_저장요청시_BadRequest() throws Exception {
        //given
        SaveTodoRequestDto dto = SaveTodoRequestDto.builder().title("제목").content("내용").priority(4L).build();
        //when
        mockMvc.perform(post("/api/todos")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(jsonStringFromObject(dto)))

                //then
                .andDo(print())
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.message",is("우선순위는 1~3 사이의 값이어야 합니다.")));
    }
}

image


이전글 Nuxt.js 배포

황준오 (Bactoria) 황준오 (Bactoria)

.

Comments

Content