본문 바로가기
Develop/Spring+JPA

[Spring] ResponseEntity vs DTO

by 연로그 2022. 8. 11.
반응형

🤔 서론 🤔

 

`줍줍` 프로젝트를 진행하며 반환값을 ResponseEntity로 반환하느냐, DTO를 반환하느냐 무엇이 더 좋을까? 에 대한 이야기가 나왔습니다. 이에 대해 다양한 사람들에게 조언을 구했고 많은 분들이 의견을 내주셨습니다 ㅎ.ㅎ 이를 정리하기 위한 글을 작성했습니다.

 


💥 ResponseEntity vs DTO 💥

 

HTTP body에 메시지를 담는 방법은 크게 2가지가 있습니다.

하나는 ResponseEntity를 이용하는 방법이고 하나는 @RestController를 사용해 DTO를 반환하는 방법입니다.

controller에 아래와 같은 메서드를 작성했다고 가정하고 살펴보겠습니다.

 

 

1. ResponseEntity 반환

  • ResponseEntity의 빌더 패턴을 이용해 HTTP 상태코드 변경 가능
// 생성
@PostMapping
public ResponseEntity<Void> save(final @RequestBody BookmarkRequest bookmarkRequest) {
    bookmarkService.save(bookmarkRequest);
    return ResponseEntity.created().build();
}

// 조회
@GetMapping
public ResponseEntity<BookmarkResponse> find(final Long bookmarkId) {
    BookmarkResponse response = bookmarkService.find(bookmarkId);
    return ResponseEntity.ok(response);
}

 

2. DTO 반환

  • @RestController라는 가정 하에 DTO로 반환 가능
  • @ResponseStatus를 통해 HTTP 상태 코드 반환 가능
// 생성
@ResponseStatus(value = HttpStatus.CREATED)
@PostMapping
public void save(final @RequestBody BookmarkRequest bookmarkRequest) {
    bookmarkService.save(bookmarkRequest);
}

// 조회
// @ResponseStatus(value = HttpsStatus.OK) -> 200인 경우 생략 가능
@GetMapping
public BookmarkResponse find(final Long bookmarkId) {
    return bookmarkService.find(bookmarkId);
}

 

 


✨ 다양한 의견 ✨

많은 분들이 자세한 답변을 해주셨다 감사합니다😄

 

 

ResponseEntity

  • 어노테이션을 쓴 코드는 숨겨진 로직이 존재한다고 느껴짐
  • return에서 어떤 응답을 생성하는지 분명하게 알 수 있음
  • 변경에 용이함

 

@ResponseStatus + DTO

  • 깔끔해보임
  • 메서드 선언부까지만 봐도 어떤 타입을 반환하는지 추측 가능
  • 응답 형태를 제한해야한다면 오히려 적합 (restrict한 반환값)

 

 

🔻 답변 원본 전문

더보기
  • 주싱님 (Twitter - @JooSing)
    • 어노테이션을 쓴 코드는 숨겨져 있는게 많은 느낌이 들어요. ResponseEntity.ok().builder() 코드를 보면 응답을 생성해서 return 한다는 '무엇' 이 코드에 직관적으로 보이고, http://bookService.save() 후에 처리한다는 '문맥'도 분명히 보이는 것 같아요.

    • 반면에 @ResponseStatus 어노테이션은 한번 설명들으면 알겠지만 직관적으로 동작이 보이지는 않는 것 같아요. 이런면에도 불구하고 어노테이션을 써서 코드작성량이 많이 줄면 사용할 것 같은데 지금 예에서는 코드작성량은 거의 동일한 것 같아요.

    • 뿐만아니라 요구사항에 변경이 생겨 반환하는 엔티티가 생기면 어노테이션 기반 코드가 변경해주어야 할 코드가 더 생기는 것도 같아요. 전 사실 스프링으로 API 를 구현하는 사람이 아니라 하나의 의견으로 참고해 주세요 : ) 공부 열심히 하시는 모습 멋지십니다!


  • 이중혁님 (GitHub - @Ramen6315)
    • https://joojimin.tistory.com/54
      저희는 ResponseEntity를 사용 하고있긴 합니다.
      사실 이유를 생각해 보진 않아서 조금 찾아봤는데 위 글이 가장 괜찮은거 같아서 공유 드려요
      글을 읽어보니 ResponseEntity 사용을 하는게 조금더 좋은것 같네요, 시간이 더 있으시다면 조금 더 찾아보시는 것도 좋을것 같아요

    • 위 정규님 말씀대로 컨트롤러 코드와 일관성을 가져가는 방향을 생각해서 정하는게 좋을 것 같아요.
      또 많은 사람들이 사용하는 방식이라는 의견은 제가 생각하기에도 정답은 아닌것 같네요.
      가능하시면 둘의 차이점을 정리 해보고 현재 상황에 맞게 둘중 하나를 선택하시는게 좋을 것 같네요


  • 김남윤님 (GitHub - @cheese10yun)
    • 우선 질문에 대한 답에 앞서서 HTTP Status Code 200, 201을 구분에 대한 필요성이 있나 라는 생각이 먼저드는데요. 일반적으로 조회 성공 200, 컨텐츠 생성 201로 사용을 하는데요. 그렇다면 사용하는 입장에서 200, 201을 유의미하게 분기해서 사용 하냐는게 중요한 관점인데요. 만약 post 생성에 대해서 201이 아니라 200을 주면 클라이언트에서 오류로 처리할것인가? 그런 제약 조건이 없다면 저는 그냥 200으로 통일하는게 더 좋다고 생각합니다. 여담 이지만 restful api 라는 디자인을 하는게 꽤나 일반적인 방법이긴 하지만 restful는 지나칠 정도로 데이터에 대한 CRUD 관점과 데이터에 대한 종속적인 방향으로 디자인이 되는 점들이 있다고 생각합니다. 데이터에 대한 행위 중심으로 설게하는게 더 유연한 설계가 된다고 생각합니다.

    • 다양한 환경이 있어서 무엇이 맞다고 말씀드리긴 어렵지만 질문에서 사용하신 코드를 보면 @ResponseStatus 사용 (+ DTO 반환) 사용 방법이 더 적절하다고 판단됩니다. 요청, 응답을 DTO로 관리하시는거 같근데 그렇다는 것은 요청/응답을 strict 하게 관리하신다는 건데요. 그렇다면 ResponseEntity을 사용 안하시는 것이 더 좋다고 생각합니다. 그 이유는 ResponseEntity을 사용 한다는거 자체가 ResponseEntity<T>객체로 해당 요청이 여러 응답 형태로 내려갈 수 있다는 의미입니다.

    • 예를 들어 조회용 API를 사용 하는 경우 200 응답에 대한 응답은 DTO로 정의되어 있고 그것으로 엄격하게 관리되는 경우라고 한다면 ResponseEntity 사용해야할 이유가 없습니다. 오히려 ResponseEntity를 사용해서 여러 객체로 응답이 될 가능성이 있다는 컨텍스트를 전달하며 혼란을 준다고 생각 합니다.또 다른 이유는 해당 컨트롤러에 대한 책임에 대한 부분입니다.

    • 만약 해당 컨트롤러가 조회에 대한 json 응답이 내려간다고 가정한다면 200에 대한 책임을 지고 그 외 4xx, 5xx는 본인의 책임 범위가 아니며 그 밖에 책임들은 다른 객체에 위임 해야 좋은 디자인이라고 생각힙니다. ResponseEntity를 사용하겠다는 말은 200 응답 뿐만아니라 4xx, 5xx에 대한 핸들링도 직접하겠다는 의미로 사용됩니다. 즉 여러가지 응답에 대한 헨들링이 필요한 지점에 사용하는 것이 적합하다고 생각합니다. 예를 들어 GlobalExceptionHandler 같은 곳 말이죠. 그렇지 않은 경우에 ResponseEntity는 적절한 대안이 아니라고 봅니다.예전에 비슷한 질문을 받아 답변들 드린 적이 있는데요. 링크 참고 하셔도 좋을거 같네요

 

이 외에도 많은 분들이 의견을 주셨습니다.

모두 감사합니다. 😄

 

 

 

👉 결론?

회사마다 다르고 팀마다 다르고 프로젝트마다 다르다!

정해진 컨벤션은 없다!

반응형