
검색 기능을 만들면서 검색 조건이 점점 많아졌다.
처음에는 각각 @RequestParam 으로 받을 수도 있었지만, 조건이 늘어날수록 컨트롤러 메서드 시그니처가 복잡해지고 가독성이 떨어질 수 있었다.
예를 들면 이런 식이다.
@GetMapping
public ResponseEntity<?> searchArtists(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) InstrumentCategory instCategory,
@RequestParam(required = false) List<Long> instIds,
@RequestParam(required = false) List<Long> styleTagIds
) {
...
}
검색 조건이 더 추가될 가능성까지 생각하면, 이 방식은 유지보수에 불리하다고 판단했다.
검색 조건을 하나의 DTO로 묶고, 컨트롤러에서는 @ModelAttribute 로 받도록 구성했다.
@GetMapping
public ResponseEntity<?> searchArtists(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) InstrumentCategory instCategory,
@RequestParam(required = false) List<Long> instIds,
@RequestParam(required = false) List<Long> styleTagIds
) {
...
}
@GetMapping
public ResponseEntity<List<ArtistSearchResponse>> searchArtists(
@ModelAttribute ArtistSearchRequest req
) {
return ResponseEntity.ok(artistSearchService.searchArtists(req));
}
@ModelAttribute 는 요청 파라미터를 보고 DTO 객체를 자동으로 바인딩해준다.
예를 들어 다음과 같은 GET 요청이 들어오면
GET /artists?keyword=플룻&instCategory=WOODWIND&instIds=1&instIds=2&styleTagIds=3
스프링은 이를 자동으로 다음과 같은 형태의 객체로 묶어준다.
new ArtistSearchRequest(
"플룻",
InstrumentCategory.WOODWIND,
List.of(1L, 2L),
List.of(3L)
)
즉, 검색 조건을 하나의 의미있는 객체로 관리할 수 있게 된다.
이번 검색 API는 GET 요청 기반이다.
일반적으로 GET 요청 검색 조건은 body가 아니라 query parameter로 전달된다.
따라서 해당 조건에서는 @ModelAttribute가 더 자연스럽다.
@RequestParam 이 괜찮은 경우
@ModelAttribute 가 더 Best 인 경우
이번 검색 API 에서는 @ModelAttribute 를 사용해 검색 조건을 하나의 DTO로 묶었다.
그 결과:
검색 조건이 늘어나는 조회 API라면 @ModelAttribute는 실용적인 선택이었다고 판단한다.