프로덕션 급 Spring Boot API — 파트 3: 일관된 응답 및 전역 예외 처리
Source: Dev.to
마이크로서비스에서 API 응답 일관성이 중요한 이유
- 서비스마다 API가 동일하게 보여야 합니다.
- 오류는 예측 가능해야 합니다.
- 클라이언트가 응답 형식을 추측할 필요가 없어야 합니다.
규칙을 지키지 않으면 다음과 같은 문제가 발생합니다:
- 엔드포인트마다 다른 응답 형식
- 불명확한 오류 메시지
try‑catch블록으로 가득 찬 컨트롤러
범용 BaseResponse 설계
범용 래퍼를 사용하면 성공 응답과 오류 응답을 모두 표준화할 수 있습니다.
public class BaseResponse<T> {
private int status;
private String message;
private T data;
// getters, setters, builder, etc.
}
API 응답에서 Builder 패턴
Builder를 사용하면 응답을 읽기 쉽고, 안전하며, 확장 가능하고, 통일된 형태로 만들 수 있습니다.
BaseResponse<String> response = BaseResponse.builder()
.status(200)
.message("Success")
.data("Hello")
.build();
장점
- 일관된 성공 응답
- 일관된 오류 응답
- API 진화가 용이
ResponseEntity와 실제 HTTP 의미론
ResponseEntity는 전체 HTTP 응답을 나타냅니다:
- 상태 코드
- 헤더
- 본문
API는 단순히 JSON 본문만 반환하는 것이 아니라 올바른 HTTP 의미론을 사용해 소통해야 합니다.
@RestControllerAdvice를 이용한 전역 예외 처리
오류 처리를 중앙 집중화하면 컨트롤러를 깔끔하게 유지하고 서비스에서 도메인‑특정 예외를 던질 수 있습니다.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<BaseResponse<?>> handleNotFound(ResourceNotFoundException ex) {
BaseResponse<?> body = BaseResponse.builder()
.status(HttpStatus.NOT_FOUND.value())
.message(ex.getMessage())
.build();
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body);
}
// other exception handlers …
}
- 컨트롤러가 깔끔해집니다.
- 서비스는 도메인 예외를 던집니다.
- 오류가 중앙에서 처리됩니다.
- 하나의 응답 형식, 하나의 위치, 중복 제로.
결론
위에서 설명한 구조는 실제 Spring Boot 마이크로서비스에서 사용하고 있는 방식입니다:
- 깔끔한 레이어 구조
- 명시적인 의존성
- 일관된 API
- 면접에서도 방어 가능한 설계
프로덕션‑급 Spring Boot는 단순히 어노테이션을 많이 쓰는 것이 아니라, 규율과 구조에 달려 있습니다. 이 글은 실제 프로젝트 경험과 정제된 개인 노트를 바탕으로 한 Production‑Grade Spring Boot API Design 시리즈의 마지막을 맺습니다.