목록 API에서 limit을 빼면 기본값 10이 적용되는데 limit=abc를 넣으면 400이 뜬다. 둘 다 '제대로 된 숫자를 안 보냈다'고 보면 이상하다. Spring은 값이 없는 요청과 값은 있는데 숫자로 바꿀 수 없는 요청을 서로 다르게 처리한다.
같은 /items 요청에서 어디서 갈리는지 보자. Spring Boot 웹 앱에 다음 컨트롤러를 추가하고, 응답에는 실제로 적용한 limit만 담아 흐름을 확인한다.
@RequestParam 기본값은 언제 10을 넣을까?
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
@RestController
class ItemController {
@GetMapping("/items")
Map<String, Integer> items(
@RequestParam(name = "limit", defaultValue = "10") int limit) {
if (limit < 1 || limit > 31) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "limit must be between 1 and 31");
}
return Map.of("limit", limit);
}
}@RequestParam은 요청에서 limit을 찾는다. 없거나 ?limit=처럼 빈 값이면 "10"을 대신 쓰고, 메서드의 int limit에 맞게 숫자 10으로 바꾼다. 기본값을 지정하면 required=false도 암묵적으로 적용된다. Spring의 @RequestParam 정의가 이 두 조건을 명시한다.
?limit=3은 값이 있으므로 기본값을 쓰지 않는다. 전달한 3이 그대로 들어간다. 여기서 기본값 10은 '항상 10 이하'라는 제한이 아니라 비어 있을 때만 채우는 값이다.
limit=abc는 왜 기본값 대신 400이 될까?
abc는 비어 있지 않다. 따라서 기본값으로 바꿀 이유가 없고, Spring은 abc를 int로 변환하려 한다. 그 변환에 실패하면 컨트롤러 본문에 들어가기 전 타입 불일치 오류가 난다. Spring MVC의 기본 예외 처리에서는 이 오류가 HTTP 400으로 연결된다. Spring MVC의 기본 예외 처리 표에서 TypeMismatchException을 확인할 수 있다.
즉, defaultValue는 잘못 입력한 값을 정상값으로 고쳐 주는 장치가 아니다. abc를 몰래 10으로 바꾸면 호출자는 오타를 알아채기 어렵다. API가 괜히 친절한 척하며 실수를 숨기는 셈이다.
limit=99도 400이라면 이유가 같을까?
아니다. 99는 숫자로 잘 변환된다. 위 예제에서는 그 다음 단계의 1..31 범위 검사에 걸려 직접 400을 낸다. 범위 검사 코드를 제거하면 defaultValue="10"만으로는 99를 막지 못한다.
| 요청 | 메서드에 전달될 값 | 결과 |
|---|---|---|
/items | 기본값 10 | 200, {"limit":10} |
/items?limit= | 기본값 10 | 200, {"limit":10} |
/items?limit=3 | 3 | 200, {"limit":3} |
/items?limit=abc | 전달 전 변환 실패 | 400 |
/items?limit=99 | 99, 이후 범위 실패 | 400 |
실제 서비스에서 99를 거부할지, 최대값 31로 줄일지는 API 계약이다. 어느 쪽이든 기본값과는 별도로 정해야 한다. 특히 목록 크기가 DB 조회량이나 응답 크기에 영향을 준다면 입력 상한을 명시하고 테스트로 고정하는 편이 안전하다.
테스트는 무엇을 나눠 확인할까?
MockMvc로 점검한다면 정상값만 한 번 호출하고 끝내지 말자. limit 누락·빈 값·숫자 오타·범위 밖 숫자를 서로 다른 입력으로 확인해야 어느 단계가 문제인지 보인다. 실패 응답의 문구까지 고정할지는 팀의 오류 응답 형식을 정한 뒤 결정하면 된다.
핵심 요약
@RequestParam(defaultValue="10")은 limit이 없거나 비었을 때 10을 채운다. abc는 값이 있으므로 기본값을 쓰지 않고 숫자 변환에서 실패한다. 99는 변환에 성공하지만 이 예제의 별도 범위 검사에서 거부된다. 요청이 막혔다면 누락·변환·범위 중 어느 단계인지 먼저 나눠 보면 된다.

