[Spring] @ResponseEntity<T> vs @ResponseBody
spring boot 프로젝트 과제 중 고민이 되던 부분이 바로 @ResponseBody와 ResponseEntity<T> 중 무엇을 사용할지였다.
찾아보던 중 좋은 블로그들이 있어 참고하여 작성해본다.(https://ksh-coding.tistory.com/89)(https://myeongdev.tistory.com/37)
1. Spring HTTP 응답 메시지 바디에 메시지를 설정하는 방법
HTTP 응답 메세지 바디에 메세지를 설정하는 방법은 다음과 같이 2가지가 존재한다.
- 반환 시 ResponseEntity<T> 사용
- @ResponseBody + 반환 객체 사용
1. ResponseEntity<T> 예제
@PostMapping("/plays")
public ResponseEntity<RaceResultResponse> registerRaceResult(@RequestBody final GameInfoRequest gameInfoRequest) {
...
}
2. @ResponseBody + 반환 객체 사용 예제
@PostMapping("/plays")
@ResponseBody
public RaceResultResponse registerRaceResult(@RequestBody final GameInfoRequest gameInfoRequest) {
...
}
2. ResponseEntity<T> vs @ResponseBody의 차이
두 가지 방법의 차이는 뭘까??
바로 ResponseEntity<T>를 사용하면 DTO 객체 반환 시보다 설정할 수 있는 부분이 더 추가된다는 점이다.
자세히 살펴보기 위해 ResponseEntity<T> 클래스를 살펴보자.
2-1. ResponseEntity<T> 클래스 (feat. HttpEntity<T>)
* ResponseEntity<T> // HTTPEntity의 확장이며, HttpStatus의 상태코그를 더 할 수 있음
public class ResponseEntity<T> extends HttpEntity<T> {
private final Object status;
...
}
---
* HttpEntity<T> // header와 body로 이뤄진 HTTP request, response entity
public class HttpEntity<T> {
private final HttpHeaders headers;
@Nullable
private final T body;
}
ResponseEntity<T>는 HttpEntity<T>를 상속하기 때문에, HttpStatus와 HttpHeader, HttpBody를 설정하여 HTTP 응답을 보낼 수 있다.
이와 달리, @ResponseBody와 객체를 사용해서는 위의 옵션을 설정하기 힘들다.
HTTP 상태 코드는 @ResponseStatus를 통해 설정해줄 수 있지만, 헤더 부분는 설정하기 힘들다.
2-2. ResponseEntity<T> vs @ResponseBody의 차이 요약
@ResponseBody
- 장점
- 어노테이션 추가만으로 간단하게 HTTP 응답을 만들 수 있다.
- 단점
- HTTP 헤더, 상태 코드 같은 옵션에 대한 유연성이 떨어진다.
- HTTP 헤더는 설정하기가 어렵다.
- 상태 코드는 @ResponseStatus를 추가로 붙여야 설정이 가능하다.
- HTTP 헤더, 상태 코드 같은 옵션에 대한 유연성이 떨어진다.
ResponseEntity<T>
- 장점
- HTTP 옵션에 대해 유연이다.(HTTP 규약을 지킨다.)
- HttpEntity를 상속 받고 있기 때문에 여러 HTTP 옵션을 설정할 수 있다.
- ResponseEntity 빌더를 통해서 여러 HTTP 옵션을 설정할 수 있다.
- HTTP 옵션에 대해 유연이다.(HTTP 규약을 지킨다.)
- 단점
- @ResponseBody 보다는 작성할 코드가 많다.
3. 그렇다면, 둘 중에 무엇을 사용할까??
ResponseEntity<T>의 단점은 @ResponseBody보다 작성할 코드가 많다는 것이었다.
하지만 ResponseEntity<T> 대신 @ResponseBody를 사용해도 눈에 띌만큼 생산성이 개선되지는 않는다고 느껴진다.
또, HTTP 옵션을 사용하지 않아도 되는 곳이라서 @ResponseBody를 사용했을 때도 추후에 HTTP 옵션을 설정해야 하도록 요구사링이 변경된다면 결국 해당 메소드도 변경된다는 단점이 있다.
그래서 HTTP 옵션을 지정해서 사용할 수 있는 ResponseEntity<T>를 사용하는 것이 훨씬 좋을 거 같다는 결론이 나왔다.
!!!! ResponseEntity를 사용할 때는 생성자 대신 빌더를 사용하자.
ResponseEntity 사용 시 생성자를 사용하면 HTTP 상태 코드를 하드 코딩으로 지정할 수 있기 때문에 잘못된 상태 코드를 넣을 수 있다.
물론 HttpStatus에 없는 코드를 넣게 되면 에러가 발생하긴 하지만 컴파일 타임이 아닌 런타임에 발생하기 때문에 좋지 않다.
따라서, ResponseEntity에 있는 빌더를 사용하면 이를 방지하고 가독성도 좋은 코드를 얻을 수 있다.
* 생성자 사용
// OK인 200을 2000으로 오타 -> 런타임 에러
return new ResponseEntity<GameResponse>(gameResponse, headers, HttpStatus.valueOf(2000));
* 빌더 사용
return ResponseEntity.ok()
.headers(headers)
.body(gameResponse);