본문 바로가기
Spring/experience

Spring Framework ResponseEntity 사용에 대한 고찰

by include_hoany 2024. 11. 17.

현업에서 Spring Framework로 Rest Api서버를 구현하다보면 ReponseEntity를 자주 보게됩니다.

Spring Framework Rest Api를 처음 공부할때는 ResponseEntity를 사용하지않고 대부분 Java 객체를 직접 응답하였는데 현업에서 기존에 있던 코드들을 확인해보니 ResponseEntity를 사용하여 Java 객체를 응답하는 형식으로 대부분 구성되어 있었습니다.

일반적으로 Java 객체를 응답해도 HTTP 프로토콜형식에 맞게 응답이 잘 되었는데 ResponseEntity를 사용하면 혹시나 내가 모르는 다른 차이점이 있나해서 눈으로 직접 확인해보기로 했습니다.
 

@PostMapping  
public ResponseEntity<OrderResponseDto> requestOrder(@RequestBody OrderRequestDto orderRequestDto) {  
    OrderResponseDto orderResponseDto = orderService.orderRequest(orderRequestDto);  
    return ResponseEntity.ok(orderResponseDto);  
}

위 코드에 도메인을 보면 주문요청 정보를 입력 받아서 주문을 처리하고 처리된 주문정보를 다시 응답하는 메소드 입니다.
 

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 48

{
  "orderId": 1,
  "storeName": "땡땡반점",
  "menuName": "짬뽕밥"
}

위 메소드의 응답대로면 위 형식으로 HTTP프로토콜 응답을 전송하게 됩니다.
 
그런데 궁금점!

@PostMapping  
public OrderResponseDto requestOrder(@RequestBody OrderRequestDto orderRequestDto) {  
    OrderResponseDto orderResponseDto = orderService.orderRequest(orderRequestDto);  
    return orderResponseDto;  
}

이렇게 따로 ResponseEntity를 사용하지 않고 응답값을 반환하게 된다면 어떻게 될지 확인해 보았습니다.
 

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 48

{
  "orderId": 1,
  "storeName": "땡땡반점",
  "menuName": "짬뽕밥"
}

ResponseEntity를 사용할때와 사용하지 않을때 응답값은 동일한걸 눈으로 직접 확인을 했습니다.

그러면 ResponseEntity를 왜 사용했을까?

    @PostMapping
    public ResponseEntity<String> requestOrder(@RequestBody OrderRequestDto orderRequestDto) {
        OrderResponseDto orderResponseDto = orderService.orderRequest(orderRequestDto);
        return ResponseEntity
                .status(HttpStatus.OK)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
                .body(orderResponseDto.toString());
    }

응답값이 json이 아닐경우 contentType을 개발자가 임의의 타입으로 변경이 필요할때 ResponseEntity를 사용하는 사례도 있고
 

@RestControllerAdvice  
public class GlobalExceptionHandler {  
  
    @ExceptionHandler(RuntimeException.class)  
    public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {  
        return ResponseEntity  
                .status(HttpStatus.BAD_REQUEST)  
                .body("Something went wrong: " + ex.getMessage());  
    }  
  
}

에러 핸들링을 할때 비록 서버에서 발생한 오류로 인해 500 응답코드가 떨어져야 하는게 맞지만 인프라 환경에서의 오류와 구분하기 위해 어플리케이션 서버에서 발생한 에러는 400으로 처리하는 사례도 보았습니다.
 

@PostMapping  
public ResponseEntity<OrderResponseDto> requestOrder(@RequestBody OrderRequestDto orderRequestDto) {  
    OrderResponseDto orderResponseDto = orderService.orderRequest(orderRequestDto);  
    return ResponseEntity.status(HttpStatus.CREATED).body(orderResponseDto);  
}

응답 상태코드를 큰 분류로 200, 300, 400, 500등으로 구분하지만 응답코드를 좀더 세분화하여 사용하는 사례도 있었습니다. 예로 201 응답코드같은 경우 클라이언트의 요청에 의해 서버에서 리소스가 성공적으로 생성되었음을 뜻하는  응답코드로 사용할 수 있습니다.

어찌되었던 ResponseEntity를 왜 사용하는지는 결국 내가 응답을 좀더 커스텀하게 Spring에서 디폴트로 설정된 부분과 다르게 HTTP 프로토콜 응답을 만들어야할때 사용한다라고 볼 수 있을것 같습니다.
 

@PostMapping  
public OrderResponseDto requestOrder(@RequestBody OrderRequestDto orderRequestDto) {  
    OrderResponseDto orderResponseDto = orderService.orderRequest(orderRequestDto);  
    return orderResponseDto;  
}

그러면 커스텀하게 HTTP 프로토콜 응답을 조절할 필요가 없을때는? ResponseEntity를 사용하지않고 전달하고자 하는 Java객체를 단순하게 리턴하여 위 코드처럼 사용해도 될것 같습니다. ResponseEntity관련된 코드를 작성하지 않았기때문에 코드의 길이도 짧아지고 가독성 이점도 있다고 생각하기에 이러한 방향성이 개인적으로는 맞다고 생각합니다.

그러나 여러 사례와 스타일을 보았지만
그 어떤 사례보다 중요한건 조직에 그라운드 룰 입니다.

프로젝트를 완성하고 유지보수 함에 있어 나혼자만 개발하는것이 아니기에 대부분 조직에서는 우리는 어떤 코드 스타일을 지향한다는 의미로 그라운드룰을 만드는경우가 많은걸로 알고 있습니다.

그라운드룰은 회고와 같은 피드백 시스템을 통해서 팀원들에 동의를 얻어 추가, 수정, 보완이 되기에 무턱대고 코드 스타일을 전체 변경하지말고 팀원들에게 설득하고 동의를 받아 진행하고 변경된 코드를 리뷰받아서 프로젝트 코드에 녹여내는게 가장 중요한 점이라고 생각합니다.
이점을 가장 중요하게 생각한다면 좋은 품질의 코드를 작성해나갈 수 있지않나란 생각이 듭니다!

그냥 사용하던 부분도 나름 정리를해서 다른 개발자분들과 공유해서 이야기를 들어보면 정말 값진 경험이 될것같으니 많이 공유하고 이야기를 나눠봐야겠습니다.