개발자는 기록이 답이다

ResponseEntity vs @ResponseStatus 차이와 동시 사용 시 발생할 문제점 본문

Spring/트러블 슈팅

ResponseEntity vs @ResponseStatus 차이와 동시 사용 시 발생할 문제점

slow-walker 2024. 4. 15. 12:40

 

프로젝트를 진행하면서 상태코드를 반환할때 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를 사용하지 않도록 해야겠습니다.

 

 

참고 블로그

https://joojimin.tistory.com/54