@RequestParam 다이렉트로 Enum 타입으로 매핑하기
Post필드에는 Enum으로 관리되는 Category필드가 있었습니다.
그리고 저는 카테고리를 Request Parameter로 입력받아 카테고리에 해당하는 게시글들을 반환하는 GET 요청 API를 만들려고 했습니다.
예상하는 uri는 /api/v1/posts?category=qna
와 같을 것입니다.
@RestController
@Slf4j
@RequestMapping("/api/v1/posts")
@RequiredArgsConstructor
public class PostApiController {
@GetMapping
public ResponseEntity<Response<Page<PostGetListResponse>>> getAllByCategory(@RequestParam String requestCategory, Pageable pageable){
Category category = Category.valueOf(requestCategory)
Page<PostGetListResponse> response = postService.getAllPostsByCategory(category, pageable);
return ResponseEntity.ok(Response.success(response));
}
}
따라서 위 코드와 같이 RequestParam은 String값으로 입력받고, 입력받은 값을 Enum타입으로 변환시켜야 했습니다.
코드가 많이 추가되어 길어지는 것은 아니지만, 입력받음과 동시에 처리된다면 코드 가독성 향상과 핵심 로직만 메서드 안에 담을 수 있을 것이라 생각되어 방법을 찾아봤습니다.
public enum Category {
QNA, COMMUNITY, STUDY, NOTICE;
public static Category create(String requestCategory) {
for (Category value : Category.values()) {
if (value.toString().equals(requestCategory)) {
return value;
}
}
throw new IllegalStateException("일치하는 카테고리가 존재하지 않습니다.");
}
}
먼저 Enum타입인 Category안에 String타입인 requestCategory를 Category로 만들어주는 메서드를 정의합니다.
public class PostEnumConverter implements Converter<String, Category> {
@Override
public Category convert(String requestCategory) {
return Category.create(requestCategory.toUpperCase());
}
}
그리고 import org.springframework.core.convert.converter.Converter;
에 있는 Converter 의 convert 메서드를 오버라이딩합니다.
Request Parameter로 입력되는 문자열을 toUpperCase를 이용해서 모든 문자를 대문자로 바꿔준 후 넘겨줍니다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new PostEnumConverter());
}
}
그리고 WebConfiguer의 addFormatters 메서드를 오버라이딩하여 만든 Converter를 추가해줍니다.
이제 잘 동작하는지 확인을 해봅니다.
/api/v1/posts?category=QNA
나 /api/v1/posts?category=qna
로 요청했을 때, 잘 동작하는 것이 확인이 되지만,
/api/v1/posts?category=
라던지 /api/v1/posts?category=hi
와 같은 잘못된 요청 시, 에러 핸들링이 되지 않음을 확인했습니다.
로그를 보니 /api/v1/posts?category=
요청처럼 존재하지 않는 문자열로 요청을 하는 경우에는 MissingServletRequestParameterException 에러가,
/api/v1/posts?category=hi
요청처럼 Enum 으로 존재하지 않는 값을 요청하는 경우에는 MethodArgumentTypeMismatchException 에러가 발생하는 것을 확인했습니다.
@RestControllerAdvice
public class ExceptionManager {
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<?> converterExceptionHandler(MissingServletRequestParameterException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Response.error(ErrorCode.REQUEST_PARAM_NOT_MATCH.getMessage()));
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<?> converterSecondExceptionHandler(MethodArgumentTypeMismatchException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Response.error(ErrorCode.REQUEST_PARAM_NOT_MATCH.getMessage()));
}
}
따라서 위와 같이 에러를 핸들링하는 ExceptionManager 를 통해 에러 처리를 진행했습니다.
정상적으로 에러 응답을 확인할 수 있게 되었습니다.