작성
·
1K
0
안녕하십니까 영한님.
영한님 덕분에 JAVA Spring 기반 백엔드 개발의
시작을 할 수 있었고,
이제는 5개월 차 스타트업 백엔드 개발자로써
커리어를 시작하게 되었습니다.
현업에 와서는 오히려
취준생 때 보다 더 많은 고민을 하게 되느데요,
질문 1. 그중 최근에 CRUD의 각 상황별 API 응답을 어떻게 보내는게 적절할지,
질문 2. 그리고 ResponseDto를 어떻게 구성하는것이 적절할지에 대한 고민을 팀장님과 함께 하고있어서,
영한님의 생각을 여쭙고자 질문글을 올리게 되었습니다.
답변 해주시면 정말 감사할 거 같습니다!
Q1. 생성, 조회 , 수정, 삭제 API의 응답을
각각 어떻게 보내시는지 여쭤보고 싶습니다.
가장 먼저 조회의 경우는
말 그대로 path의 Entity 및 관련된 Entity 정보를 조합하여 응답 DTO로 변환하여 보내고 있습니다.
그런데 나머지 Write Operation에 대한 응답을 어디까지 보내야 하냐가 이슈 입니다.
예를들면 엔티티의 생성의 경우
엔티티의 응답 DTO를 보내면 - 프론트에서 별도의 조회 API 호출 없이 바로 프론트가 화면에 뿌려줄 수 있으니깐
저는 생성의 경우에도 조회와 마찬가지로 Entity의 정보를 조합하여 응답 DTO로 변환하여 보내고 있었습니다.
그런데 이러한 부분이 Command Query Sperate 원칙에 어긋나는것 같아,
영한님께서는 혹시 생성한 Entity의 Key만 보내시는지,
아니면 Entity의 정보를 DTO로 변환하여 보내시는지 궁금합니다.
만약 Entity의 Id만 보내신다면 이후에 별도로 조회API를 호출해야 하고 그 또한 비용일텐데
이러한 부분은 어떻게 하시는지 여쭤보고 싶습니다.
이제 수정 API인데요,
제가 다룬 비즈니스 로직의 경우
수정 비즈니스 로직이 다양하고 ,
각 비즈니스 로직의 경우 다뤄지는 Entity의 종류가 다른 경우였습니다.
(중심 Entity는 동일하지만,
연관된 Entity를 누구까지 건드리냐의 차이)
그래서 하나의 통일된
응답으로 보내기 모호한 점이 첫 번째 이유이고,
애초에 수정 후에 프론트 화면에서 그 엔티티의 정보를 보여줄 필요가 없어서
라는 두번째 이유에 의해서
에초에 엔티티의 Id값도 보내지 않고 있었는데요,
이 수정 API의 응답을 영한님은 어떻게 진행하지는지 그 이유가 궁금합니다.
마지막으로 삭제의 경우는 정말,
프론트에게 보낼 응답이 없어도 되는 경우 라고 생각했는데요,
팀장님의 의견은 만약에 나중에 삭제한 Entity를 복구하는 요구사항이 추가되는것을 고려하여
Id 정도는 넘기자는 의견을 내어주셨습니다.
마찬가지로 삭제의 경우도 어떤식으로 수행하시는지 그 이유가 궁금합니다.
Q3. 마지막으로 Entity의 ResponseDto의 필드를 어떤식으로 구성하시는지 궁금합니다
예를들면 저의 경우는 API는
프론트와 서버 간의 스펙이라고 생각하고,
Entity의 단건조회의 경우는 단건 조회용 ResponseDto를,
전체조회의 경우는 전체 조회용 SummaryResponseDto를 별도로 만들어서 사용하고 있었습니다.
저희 팀장님 께서는 프론트쪽도 일을 해오시다가 ,
백엔드쪽 분야로 전향하신 케이스 인데요,
그렇다 보니 어떻게 해야 프론트의 생산성이
올라가는지를 고려하시는 분이셨고,
팀장님의 생각은 서버에서 넘겨주는 응답에 일관성이 있어야
그 응답을 사용하는 프론트 측도 학습이 되고 놓치는 부분 없이 생산성이 올라간다는 의견이셨습니다.
그래서 Entity별로 당장 사용하지 않더라도 가능한 모든 필드를 담은 ResponseDto를 하나만 만들고,
해당 ResponseEntity의 조합으로 각 API별 응답 Dto를 만들어서 사용하면 ,
프론트 측 에서는 일관성 있는 응답값을 사용할 수 있다는 의견이셨습니다.
물론 이 방법이 네트워크 패킷의 양을 쓸데없이 증가시킨다는 것을 알고 계시면서도,
생산성에 큰 영향을 미치는 부분이라고 생각하셨습니다.
예를들어 다음과 같이 각 Entity의 응답 Dto의 조합별로 API의 ResponseDto를 만들 수 있습니다.
ResponseDto{
UserDto{
id : 1,
name : “aaa”
… // User엔티티의 거의 모든 필드
}
ItemDto{
id : 2,
name : “bbb”,
… // Item엔티티의 거의 모든 필드
}
}
저는 이러한 부분에 대해 생각해 본 적이 없이,
그냥 제가 “해당 API를 호출하는 화면에서 필요한 정보들만을 담아 (혹은 여러 화면에서 쓰인다면 여러개를 고려) ResponseDto를 각각 만들어서” 넘겼는데요
영한님께서는 이러한 ResponseDto를 구성하는 부분에 있어서
상황별로 필드를 재구성 하여 ResponseDto를 정의하여 사용하시는 편 인지 (SummaryResponseDto 등의 별도 Dto에 사용될 Entity의 필드들을 풀어서 정의하시는지)
아니면 생산성을 고려하여 각 Entity별 Dto를 만들고, 이들을 조합하여 ReponseDto를 정의하시는 편 이신지 ,
혹은 다른 규칙이 있으신지 궁금합니다.
물론 그렇다고 ,
팀장님의 의견에서
전체조회시 사용하는 DTO와 단건조회시 사용하는 DTO가 동일하더라도,
전체조회 후 단건조회를 할때 단건조회 API를 호출하지 말고 기존 Front가 가지고 있는 값을 쓰지는 말자는 의견 이십니다 (단건조회API는 별도로 호출해야 한다)
그저 핵심은 프론트가 다루는 ResponseDto의 일관성을 위해서 입니다 (결론은 생산성을 위해)
긴글 읽어주셔서 감사합니다.
항상 건강하셨으면 좋겠고,
다음 강의들도 손꼽아 기다리고 있습니다!
답변 2
5
안녕하세요. khd1692님
우리가 API 디자인을 할 때 중요하게 생각해야 하는 부분이 있습니다.
바로 API를 사용하는 클라이언트의 입장을 적극 고려애햐 하는 부분입니다.
Q1. 생성, 조회 , 수정, 삭제 API의 응답을
각각 어떻게 보내시는지 여쭤보고 싶습니다.
- 이 부분은 성능과 디자인의 트레이드 오프에서의 선택입니다. ID만 보내도 되고, 값을 함께 보내도 됩니다.
그런데 저의 경우 ID만 보내고 나머지를 다시 조회하는 방식을 선호합니다.
이렇게 하면 데이터 저장과 조회를 깔끔하게 분리할 수 있기 때문이지요.
물론 ID로 데이터를 다시 조회한다면 조금이라도 시스템의 부하가 늘어나는 것은 사실입니다.
그런데 대부분의 시스템은 복잡한 조회 때문에 성능이 떨어지는 것이지 PK 기준으로 데이터를 조회하는 것은 시스템 전체로 보면 아주 미미한 영향을 가지게 됩니다.
Q2. 엔티티 ID를 응답으로 남기는 것이 좋나요?
HTTP 상태 코드로 응답을 알 수 있기 때문에 변경, 삭제의 경우 ID를 남기고 남기지 않는 것 또한 선택입니다.
다만 변경, 삭제를 요청한 곳에서 응답에 ID를 받을 수 있으면 코드를 더 편하게 작성할 수 있는 부분들이 있을 수 있습니다.
예를 들어서 삭제를 요청한 클라이언트가 비동기 콜백으로 요청하게 되면 응답에 ID가 없으면 ID를 어딘가에 관리해야 하는데, 응답에 ID를 받을 수 있으면 더 편리하게 코드 작성이 가능해집니다.
이런 API 디자인의 경우 클라이언트의 편리함과 상황도 함께 고려하는것이 좋습니다.
Q3. 마지막으로 Entity의 ResponseDto의 필드를 어떤식으로 구성하시는지 궁금합니다
이 부분은 성능 보다는 유지보수 관점에서 고민하는 것이 필요합니다.
API에 필요한 데이터를 모두 노출해두면 이후에 클라이언트가 필요한 기능을 찾아서 사용만 하면 되기 때문에 서버에서 기능을 변경할 일이 줄어듭니다.
반면에 이 방법은 서버에서 데이터를 변경하는 경우, 너무 많은 데이터가 노출되어 있기 때문에 서버쪽 변경을 어렵게 할 수 있습니다. 예를 들어 API에 노출되지 않은 데이터는 서버에서 자유롭게 변경할 수 있지만, 이미 노출한 데이터는 클라이언트에서 정말 사용하는지 일일이 확인한 다음에 변경해야 하기 때문에 서버쪽 데이터 변경을 어렵게 할 수 있습니다.
결국 모든 데이터를 오픈하는 것과 일부 데이터를 오픈하는 것은 트레이드 오프가 있습니다. 이런 트레이드 오프를 고려할 때 다음과 같은 관점을 보시면 도움이 되실거에요.
이런 고민은 크게 2가지 관점으로 보는 것이 주요합니다.
1. API를 호출하는 웹 프론트엔드 코드와 서버 코드를 함께 변경할 수 있다. (한팀이다.)
2. API를 호출하는 클라이언트와 서버 코드를 함께 변경할 수 없다. (다른팀이다.)
웹 프론트엔드와 서버 코드를 함께 유지관리하는 경우 엔티티의 데이터들을 전달해두면, 이후에 화면에 기능이 추가될 때 웹 프론트엔드 코드만 고치면 되기 때문에 유연한 변경이 가능합니다. 물론 서버쪽 코드를 변경하는 경우 웹 프론트엔드 개발자가 이 데이터를 정말 사용하는지 확인하는 과정도 같은 팀이기 때문에 상대적으로 쉬울 수 있습니다.
API를 호출하는 클라이언트가 다른 팀이거나 다른 회사라면, 한번 노출한 API의 데이터는 거의 변경이 불가능합니다. 따라서 꼭 필요한 데이터만 노출하는 것이 좋습니다.
전체 조회 API에 모든 데이터 포함 vs 둘을 분리
추가로 전제 조회에 모든 데이터를 추가해서 단건 조회를 거의 사용하지 않는 방법과
전체조회 API와 단건 조회 API를 분리하는 것은 트레이드 오프가 있습니다.
이것에 대한 선택은 비즈니스에 따라 달라집니다.
리스트 화면과 상세 화면이 둘다 매우 단순하다면 전체 조회 API 하나에 구성하는게 더 나은 방법이 될 가능성이 있습니다. 이 경우 거의 로컬에서 화면 변경이 어루어 진다면 사용자가 느끼는 속도가 매우 빠르겠지요?
하지만 리스트 화면은 데이터가 몇게 없는데 상세 화면에 데이터가 너무 많다면, 이것은 둘을 분리하는 것이 더 나은 방법이 될 가능성이 있습니다. 리스트 화면 자체를 불러오는데 속도가 오래 걸리고 네트워크를 많이 사용하기 때문이지요.
도움이 되셨길 바래요.
0
안녕하세요 khd1692님, 인프런 AI 인턴이에요.
질문에 답변드리겠습니다.
질문 1. CRUD의 각 상황별 API 응답 방법에 대해서 어떻게 하는 것이 적절한지
CRUD의 각 상황별 API 응답은 일반적으로 다음과 같이 처리됩니다:
하지만 실제 응답 방식은 개발자의 판단에 따라 다를 수 있으며, 상황에 맞추어 결정하는 것이 중요합니다. 일관성과 생산성, 그리고 사용하기 편한 응답 형태를 고려해야 합니다.
질문 2. ResponseDto 구성 방식에 대한 고민
ResponseDto의 구성 방식은 목적과 요구사항에 따라 다를 수 있습니다. 몇 가지 고려할 점은 다음과 같습니다:
따라서, 각 상황에 맞춰 필요한 정보만을 포함시키고, 일관성과 생산성을 고려하여 ResponseDto를 구성하시면 됩니다.
팀장님의 의견에 따라 하나의 응답 DTO를 정의하고, 필요한 필드를 포함시키는 방식도 가능하며, 그 외에도 Entity별로 별도의 Dto를 만들고 이를 조합하여 ResponseDto를 구성하는 방식도 가능합니다. 어떤 방식이든 일관성을 유지하고 프론트엔드 개발자의 생산성을 고려하는 것이 중요합니다.
마지막으로, 삭제 API의 경우 성공/실패 여부를 응답으로 보내도 되지만, 팀장님의 의견처럼 삭제한 엔티티의 Id를 보내는 경우도 있습니다. 이후에 복구 요구사항이 추가될 가능성이 있을 때는 Id를 보내는 것이 유용할 수 있습니다.
감사합니다. 앞으로도 좋은 강의를 기다려주셔서 감사합니다!