개발자는 기록이 답이다
ResponseEntity vs @ResponseStatus 차이와 동시 사용 시 발생할 문제점 본문
프로젝트를 진행하면서 상태코드를 반환할때 ResponseEntity와 @ResponseStatus 를 동시에 사용했었는데요.
아래와 같이 PR 리뷰를 받게 되어 자세히 알아보고자 포스팅하려고 합니다.
일반적으로 REST API를 만들 때 @RestController를 사용하여 JSON 형식으로 응답을 반환합니다. 이는 프론트엔드와 API가 연동될 때 상태 코드를 전달해야 하는 이유가 있습니다. 프론트엔드는 서버로부터 받은 상태 코드를 기반으로 다음 동작을 결정하기 때문입니다.
이러한 상황에서는 ResponseEntity나 @ResponseStatus를 사용하여 상태 코드를 반환할 수 있습니다. 이 둘 간의 차이를 이해하기 위해 먼저 각각의 개념을 살펴보고, 동시에 사용할때 어떤 문제가 발생하는지 알아보겠습니다.
1. ResponseEntity란?
ResponseEntity는 HttpEntity를 확장하여 HTTP응답의 상태코드를 포함하는 클래스 입니다.
이 클래스는 Spring Framework에서 주로 사용되며, RestTemplate 및 Spring MVC의 @Controller에서 사용됩니다.
SpringMVC의 @Controller 메소드에서 ResponseEntity를 반환하여 HTTP응답을 제어하는 예제는 아래와 같습니다.
HTTP 응답 상태코드 뿐만 아니라 헤더 및 본문을 명시적으로 설정해 유연하게 응답을 제어할 수 있습니다.
// setter 사용
@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ...;
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setLocation(location);
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}
// 빌더 패턴 사용
@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ...;
return ResponseEntity.status(HttpStatus.CREATED)
.location(location)
.header("MyResponseHeader", "MyValue")
.body("Hello World");
}
2. @ResponseStatus 란?
@ResponseStatus 어노테이션도 HTTP응답의 상태 코드와 이유(reason)을 지정하는데 사용됩니다. 주로 Spring MVC에서 예외 처리를 할때 사용되며, 예외가 발생했을 때 클라이언트에게 반환되는 상태코드를 명시적으로 지정할 수 있습니다.
예를 들어, 예외클래스에 @ResponseStatus 어노테이션을 사용하면 해당 예외가 발생했을때 자동으로 지정된 상태 코드가 HTTP응답으로 반환됩니다.
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
// 예외 클래스 내용
}
물론 예외 클래스 말고도 제가 PR날렸던 코드 처럼 controller에서도 사용할 수 있습니다.
컨트롤러의 해당 메소드가 호출될 때 지정된 상태 코드가 HTTP응답으로 반환됩니다.
@RequestMapping(value = "/create", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public String createResource() {
// 리소스 생성 로직
return "Resource created successfully";
}
ResponseEntity와 다른 점은 @ResponseStatus 어노테이션을 사용하게 되면 header와 body와 같은 추가적인 응답 처리가 불가능합니다.
따라서 Controller에서는ResponseEntity를 사용하고, 예외 클래스에서는 @ResponseStatus를 사용하는게 적합합니다. 예외 처리에 대한 응답 body의 경우 @ControllerAdvice 혹은 @ExceptionHandler에서 처리하면 됩니다.
3. Controller에서 둘 다 동시에 사용하지만 상태코드가 다르면 어떻게 될까?
결론부터 말하자면 Controller에서 ResponseEntity와 @ResponseStatus를 동시에 사용할때에는 ResponseEntity에서 명시된 상태코드가 우선됩니다. 즉, ResponseEntity에서 명시된 상태코드가 HTTP 응답으로 반환됩니다.
하지만 응답이 2번 발생할 수 있기 때문에 동시에 2개를 사용하는 것은 권장되지 않고, 하나만 사용하는것이 좋습니다.
또한 아래와 같이 (제가 한 실수,,) 응답코드를 Created와 Ok를 둘 다 사용한다면 다른 개발자가 코드를 읽을때 혼동을 줄 수도 있습니다. 따라서 휴먼 에러를 방지하기 위해 왠만하면 Controller에서 @ResponseStatus를 사용하지 않도록 해야겠습니다.
참고 블로그
'Spring > 트러블 슈팅' 카테고리의 다른 글
Nginx로 Reverse Proxy 서버를 구축해서 로드밸런싱하기 (0) | 2024.05.03 |
---|---|
쿼리 최적화를 했지만 부족하다면, Parallel Stream으로 성능 개선하기 (0) | 2024.04.29 |
비동기 쿠폰 발급 알림 기능에서 SSE를 선택한 이유 (0) | 2024.03.25 |
@UtilityClass란? (0) | 2024.03.25 |
트러블 슈팅 - 테스트코드도 코드이므로 합성을 통해 중복을 없애자 (0) | 2024.03.16 |