API Response 구조: data 래핑, 해야 할까?
프로젝트를 진행하면서 백엔드 API Response 구조에 대한 흥미로운 논의가 있었다.
초기 설계: data 래핑 방식
{
"status": 200,
"message": "리뷰가 성공적으로 수정되었습니다.",
"data": {
"reviewId": 123,
"storeId": 1,
"content": "너무 맛있어요!",
"rating": 3,
"userId": "user01",
"photos": "abc.png",
"createdAt": "2025-09-29T10:15:00",
"modifiedAt": "2025-09-29T10:20:00"
}
}
처음에는 이런 구조가 당연하다고 생각했다. 프론트엔드에서 작업할 때도 response.data로 데이터를 꺼내는 게 익숙했고, 성공 여부를 명확히 확인할 수 있어서 좋았다.
튜터님의 피드백
하지만 튜터님께서 "요즘은 꼭 이렇게 하지 않는다"는 의견을 주셨다. data로 한 번 더 감싸지 않고 직접 응답 데이터를 반환하는 방식도 많이 사용된다는 것이었다.
팀의 결정
팀원들과 회의 끝에 data 래핑을 제거하기로 결정했다.
{
"reviewId": 123,
"storeId": 1,
"content": "너무 맛있어요!",
"rating": 3,
"userId": "user01",
"photos": "abc.png",
"createdAt": "2025-09-29T10:15:00",
"modifiedAt": "2025-09-29T10:20:00"
}
확실히 더 깔끔해진 느낌이다. HTTP 상태 코드와 응답 구조만으로도 충분히 성공/실패를 판단할 수 있고, 불필요한 중첩을 줄일 수 있었다.
회고
사실 "정답"은 없는 것 같다. 중요한 건 팀 내에서 일관된 컨벤션을 유지하는 것. data 래핑은 에러 처리나 메타데이터를 함께 전달할 때 유용할 수 있지만, 단순한 CRUD API에서는 오히려 과한 설계일 수 있다는 걸 배웠다.
가격 데이터 중복: 정규화 vs 스냅샷
두 번째로 고민했던 건 데이터베이스 설계, 특히 가격 정보의 중복 저장 문제였다.
ERD 구조
우리 프로젝트는 다음과 같은 구조였다:
- menu 테이블: 메뉴 기본 정보 및 가격
- order 테이블: 주문 정보 및 총 가격
- order_item 테이블: 주문 항목별 가격
내가 제기한 의문
회의 중에 "3개 테이블에 가격이 중복되는데, 나중에 값이 수정되면 위험하지 않을까요?"라고 질문했다. 데이터베이스 정규화를 생각하면 중복은 피해야 하는 게 당연한 거 아닌가?
집중 공격(?)을 받다
그런데... 생각해보니 내가 완전히 잘못 생각하고 있었다. 😅
핵심은 이거였다:
- menu.price: 현재 메뉴의 가격 (언제든 변경 가능)
- order_item.price: 주문 당시의 메뉴 가격 (스냅샷)
- order.total_price: 주문 당시의 총액 (스냅샷)
오늘 5,000원이던 햄버거가 내일 6,000원이 되더라도, 어제 주문한 내역은 5,000원으로 남아야 한다. 이건 중복이 아니라 시점의 차이를 기록하는 것이었다!
팀의 최종 결정
논의 끝에 팀은 order 테이블에서 total_price 컬럼을 제거하기로 했다. 필요할 때마다 order_item의 가격들을 합산해서 계산하자는 의견으로 모아졌다.
내 생각
개인적으로는... 조금 아쉽다. 🤔
물론 계산으로 구할 수 있는 값이긴 하지만:
- 주문 조회가 빈번한 시스템에서 매번 합산 계산을 하는 게 효율적일까?
- 총액은 주문 생성 시점에 확정되는 값인데, 굳이 저장하지 않을 이유가 있을까?
- 나중에 할인이나 쿠폰 같은 기능이 추가되면 어차피 총액을 저장해야 하지 않을까?
하지만 팀의 결정을 존중한다. 실제로 서비스를 운영해보면서 성능 이슈가 생기면 그때 다시 추가해도 늦지 않을 것 같다.
배운 점
- API 설계에 정답은 없다: 상황과 팀의 컨벤션에 맞게 선택하면 된다
- 중복 ≠ 나쁜 것: 시간에 따라 변하는 데이터의 경우, 스냅샷을 저장하는 것이 오히려 필수
- 질문하는 용기: 내 의견이 틀렸더라도 질문을 던지면서 팀 전체가 함께 고민할 수 있었다
- 정규화의 함정: 무조건적인 정규화가 항상 옳은 건 아니다. 비즈니스 요구사항을 먼저 고려해야 한다
다음에는 더 깊이 고민하고 질문해야겠다. 그래도 이런 토론 과정이 있어서 더 많이 배우는 것 같다! 💪
'👍코드 회고' 카테고리의 다른 글
| 장바구니 코드 속 store_id는 어디에 둘까? (10.15) (0) | 2025.10.15 |
|---|---|
| 서비스단 깔끔하게 하기 (10.02) (0) | 2025.10.03 |
| 스프링 개발 회고 (10.01) (0) | 2025.10.01 |
| 스프링 개발 회고 (09.30) (0) | 2025.10.01 |
| ERD 설계 회고 (09.27) (0) | 2025.09.27 |