서론
스프링을 사용할 때 컨트롤러에서 직렬화할 데이터를 반환할 때 @ResponseBody를 사용할 지 ResponseEntity를 사용할 지 토론이 이어졌다.
무엇을 사용하는게 좋을 지 살펴보자.
본론
@ResponseBody
@ResponseBody는 스프링 버전 3.0에 등장한 녀석이다. 이 녀석을 사용한다면 반환값을 HttpMessageConverter를 통해 응답 바디로 직렬화할 수 있다.
위 코드는 스프링 @ResponseBody의 코드이고 아래는 @ResponseBody 사용 예시이다.
/reservations 로 GET 요청이 올 때 동작하는 메서드인데 @ResponseBody 사용방법이라고 해놓고 @ResponseBody 애노테이션은 보이지도 않는다.
무슨일인걸까??!!!
정답은 @RestController에 있다.
@RestController 애노테이션은 @Controller와 @ResponseBody를 합쳐놓은 애노테이션이다. 때문에 클래스 레벨에 @RestController를 붙여준다면 @ResponseBody를 생략해도 된다!
덕분에 @RestController를 사용한다면 아주 깔쌈하게 데이터를 직렬화할 수 있다. 참고로 @RestController는 스프링 버전 4.0에 등장하였다.
ResponseEntity
ResponseEntity는 @ResponseBody 보다는 조금 늦은 버전 3.0.2에 등장하였다.
ResponseEntity는 Http 상태 코드를 가지고 있고, Http 헤더와 바디를 가지고 있는 HttpEntity(스프링 버전 3.0.2에 등장)를 상속하는 구조로 되어 있다.
Http 상태 코드를 변경하고 싶다거나 헤더를 수정하고 싶다면 ResponseEntity를 사용하면 된다.
정리해보자면 객체를 json으로 직렬화한다는 점에서는 동일하지만 ResponseEntity를 사용한다면 HTTP 헤더, 상태 코드를 수정할 수 있다는 장점이 있다. 반면 @ResponseBody와 @RestController를 사용한다면 보다 간결하게 직렬화할 수 있다.
물론 @ResponseBody를 사용한다고 해서 HTTP 상태코드를 변경하지 못하는 것은 아니다. 기본 값이 200이고, @ResponseStatus 애노테이션을 사용하여 HTTP 상태코드를 변경할 수 있다.
하지만 동적으로 상태코드를 변경할 수 없다는 단점이 있다. 예를 들어 예약을 삭제하는 메서드가 있다. 이 메서드의 파라미터로 id가 넘어오는데 존재하는 id라면 204를 반환하고, 존재하지 않는 id라면 404를 반환해야 하는 상황이 있다고 가정하자. @ResponseStatus는 이렇게 상황에 따라 상태 코드 변경이 불가하고 한 메서드에 하나의 상태 코드만 반환할 수 있다.
들었던 의문점이 있다. HTTP 상태 코드를 수정하거나 헤더를 수정할 일이 없다면 불필요하게 ResponseEntity로 객체를 매핑할 필요 없이 그냥 @ReseponseBody를 사용하는 게 효율적이라고 생각했다. 하지만 간결하게 @ResponseBody를 사용해도 될 상황인데도 대부분이 ResponseEntity를 사용하고 있었다. 여기서 말하는 대부분은 우테코 팀프로젝트 코드들이다.
HTTP 상태 코드를 수정할 일도 없고, 헤더를 수정하는 경우가 아니여도 99.9% ResponseEntity를 사용하고 있었다. 딱 하나 ResponseBody를 사용한 코드를 찾았는데 ping pong 테스트 용이였다. ㅎ
결론
Simple is best라면 @ResponseBody를 사용하고, 변화에 유연하게 대처하고 싶다면 ResponseEntity를 사용하면 될 거 같다. 아니면 팀 컨벤션에 맞추자.
번외1
ResponseEntity를 사용하여 HTTP 상태 코드를 변경하고 또 @ResponseStatus를 사용하여 상태 코드를 변경한다면 누구의 상태 코드를 반환할까 궁금해서 실험해보았는데 결과는 ResponseEntity의 상태 코드를 따랐다.
번외2
ResponseEntity를 사용하지 않고 헤더의 값을 설정하는 방법이 없을까 엄청 찾다가 과거에서 답을 얻었다.
방법은 서블릿을 사용하는 것이다. HttpServletResponse를 파라미터로 받은다음 헤더를 설정해주면 된다!
번외3
스프링을 사용할 때 Entity를 db에 저장되는 도메인 객체로 정의하고 사용하고 있었다. 하지만 우리는 ResponseEntity에 보통 엔티티를 담는게 아니라 dto를 담아 넘긴다. 그럼 dto도 엔티티인가? 라는 생각이 문득 들었고 뭔가 적절치 않은 네이밍이라고 생각이 되었다.
그래서 ResponseEntity와 @ResponseBody로 테코톡을 준비하는 제제에게 질문을 던졌다.
엔티티를 HTTP가 응답하는 값들 헤더나 바디나 상태코드나 등등을 전부 포함하는 의미로 사용된게 아닐까라고 답변을 주었다.
답변을 받고 ResponseEntity와 @ResponseBody 중 뭘 사용해야할지 감이 잡힌 것 같다. 내가 반환해야 하는게 body라면 @ResponseBody 를 사용하고 내가 반환해야 하는게 엔티티라면 ResponseEntity를 사용하면 될 거 같다. 👍
'Spring' 카테고리의 다른 글
[Spring] 스프링 빈 프로퍼티 애노테이션 @Profile, @Order (4) | 2024.11.14 |
---|---|
[Spring] 금쪽이 Server-Sent-Event (SSE) (0) | 2024.10.07 |
[Spring] 우리집을 못 찾겠군요 (feat: @RestControllerAdvice, @Order) (1) | 2024.08.18 |
[Spring] 액추에이터 Actuator (0) | 2024.08.05 |
[Spring] 애플리케이션과 테스트 동시에 실행하기(RestAssured 포트설정) (1) | 2024.05.04 |