8단계
8단계 — Spring MVC 요청 경계와 실패 계약
1회 조회
목차
Controller가 동작한다고 API 경계가 완성되는 것은 아닙니다. 요청 파싱, 인증, 입력 검증, 업무 규칙, 트랜잭션, 외부 호출을 한 메서드에 모으면 실패 원인과 테스트 범위가 뒤섞입니다.
얇은 Controller를 만든다
Controller는 HTTP를 업무 입력으로 번역하고 결과를 HTTP 응답으로 바꿉니다. Service는 업무 규칙과 트랜잭션을 소유하고 Repository는 저장소 세부 구현을 감춥니다. 클라이언트가 보낸 사용자 ID보다 인증 principal을 신뢰하고, body와 path의 자원 ID가 충돌하면 거절합니다.
@PostMapping("/items")
ResponseEntity<ItemResponse> create(
@AuthenticationPrincipal UserPrincipal principal,
@Valid @RequestBody CreateItemRequest request) {
var result = itemService.create(principal.id(), request.toCommand());
return ResponseEntity.status(201).body(ItemResponse.from(result));
}
오류도 API 계약이다
검증 실패, 인증 없음, 권한 없음, 자원 없음, 상태 충돌, 외부 의존성 timeout을 서로 다른 안정된 error code로 보냅니다. stack trace와 공급자 원문은 응답에 넣지 않습니다. 쓰기 요청에는 idempotency 또는 중복 방지 키를 검토하고, 외부 호출에는 deadline과 bounded retry를 둡니다.
책임 경계
HTTP 매핑·검증 결과·상태 코드
업무 불변식·권한·트랜잭션
SQL·외부 프로토콜·timeout
완료 기준
- 정상·검증 실패·권한 거절·충돌·timeout 응답이 문서화된다.
- Controller 테스트와 실제 DB 통합 테스트의 책임이 구분된다.
- 느린 외부 호출이 요청 스레드를 무제한 점유하지 않는다.
- 오류 응답에 비밀·SQL·stack trace가 노출되지 않는다.
관련 용어: Spring MVC
이 글에서 만나는 용어
🎉 Spring Boot 4 로 시작하는 백엔드 완주를 축하해요
이어서 어떤 걸 배워 볼까요?