[뚝배기] RESTful한 API 작성하기
어제부로 일주일 간 진행되는 스프링 심화 프로젝트를 시작했다. 배달의 민족을 벤치마킹한 프로젝트이다.
어제는 하루종일 유저 시나리오부터, ERD 설계, API 명세서 작성을 하느라 회의만 했다. 팀 내에 자신의 의견을 굉장히 설득력 있게 전달하시는 분이 계셨는데, 회의가 쉽지는 않았지만 그 분을 보며 회의나 협업 과정에서 ‘어떻게 말해야 효과적인지’를 배울 수 있는 시간이었다.
상대방의 말을 끝까지 경청하기
당연한 일이지만 실제 상황에서는 쉽지 않다. 끊지 않고 듣는 연습이 필요하다.
겸손한 자세로 말하기
내 의견이 정답이라는 태도보다, 함께 더 나은 방향을 찾는다는 마음으로.
의견은 명확하게, 근거를 들어 설명하기
감이 아니라 이유를 말해야 신뢰를 얻을 수 있다. 자료나 경험을 근거로 제시하면 효과적이다.
API 명세서 작성 중, 맞닥뜨린 문제를 해결한 방법을 회고하고자 한다.
내가 담당한 도메인은 '주문'으로, 회원이 주문을 요청하고, 사장님이 주문을 수락하는 로직이 포함된다.
주문 내역 조회 API
내가 첫 번째로 고민한 API는 "주문 내역 조회"이다.
이 API는 일반 회원과 사장님 모두 사용할 수 있으며, 각자 자신의 주문 내역만 조회할 수 있다. 단, 사장님은 회원의 전화번호를, 일반 회원은 리뷰 작성 가능 여부를 추가로 받아야 한다는 점에서 응답 데이터에 차이가 있다.
이 API는 두 가지 방식으로 구현이 가능했다:
- 일반 회원용, 사장님용 API를 구분: 각각 별도의 엔드포인트(orders/user, orders/owner)로 나누는 방식
- 하나의 API에서 사용자 역할에 따라 분기 처리: 사용자 정보를 기준으로 응답 데이터를 조절하고, 불필요한 필드는 null 처리


여기서 API는 두 가지 방법으로 구현 가능하다.
- 일반 회원용, 사장님용 API 구분:
- GET /orders/user
- GET /orders/owner
- 일반 회원과 사장님은 쿼리 파라미터로 구분하고, 하나의 API로 진행. 단, 서로에게 불필요한 응답은 NULL로 처리.
- GET /orders/role=user(혹은 owner)
각 방법의 장단점을 생각해보았다.
1번은 깔끔하게 응답을 내려줄 수 있다. 하지만 코드와 엔드포인트가 늘어나서 유지보수가 부담스럽다. 또한 중복되는 로직을 작성하게 될 수도 있다.
두 번째로 방법은 응답 데이터가 조금 복잡하다. 하지만 API 개수도 줄이고, 코드 수도 줄일 수 있다. 또한 엔드포인트도 RESTful 하게 작성할 수 있다.
내가 선택한 방법은 2번이다. 왜냐하면, 추가적으로 내리는 응답은 보안상 민감하지 않은 데이터이며, 프론트에서 필요한 데이터만 사용하면 된다고 생각한다. 만약, 데이터가 보안상 중요하다면 API를 분리하는 게 나아보인다. 또한 현재로서는 API와 레이어별로 메소드를 추가적으로 생성하는 것에 대한 리소스 낭비가 더 심해보인다.
주문 상태 변경 API
두 번째로 고민한 API는 "주문 상태 변경"이다.
일반 회원은 상태가 Waiting인 주문을 취소할 수 있고, 사장님은 상태를 수락, 거절, 배달 등으로 변경할 수 있다.
모두 결국 Order 테이블의 status 컬럼을 변경하는 로직이지만, 권한(인가) 처리와 상태 전이에 대한 예외처리가 서로 다르다.
여기서도 API는 두 가지 방법으로 구현 가능하다.
- 일반 회원의 주문 취소, 사장님의 주문 상태 변경 API 구분:
- PATCH /orders/cancel
- PATCH /orders?status=accept(reject,cooking,delivering,delivered)
- 하나의 API로 진행.
- PATCH /orders?status=accept(cancel,reject,cooking,delivering,delivered)
각 방법의 장단점을 생각해보았다.
1번은 로직 구분이 깔끔하다. 하지만 한 API에서 모든 역할을 처리함으로써 if-else가 많아지고, 예외 흐름도 복잡해져서 오히려 유지보수가 어려워질 수 있다.
두 번째 방법은 API 개수는 줄어들어 관리 포인트가 감소하지만, 한 API에서 인가 로직 + 상태 전이 로직 + 예외 분기까지 모두 다뤄야 하기 때문에 코드 복잡도가 증가한다.
그래서 내가 선택한 방식은 1번이다.
왜냐하면, 인가 처리나 상태 전이 규칙처럼 역할에 따라 명확히 달라지는 로직은 분리하는 것이 유지보수 측면에서 훨씬 효율적이라고 판단했기 때문이다.
하나로 합쳐서 관리하는 것보다, 명확하게 나눠 관리하는 게 장기적으로는 코드의 가독성과 안정성에 도움이 된다고 생각한다.
결론
인가도 같고, 분기도 적고, 구조도 단순하다면 → 통합
복잡도나 책임이 커지기 시작하면 → 분리
API 설계에 정답은 없다.
상황에 따라, 팀의 스타일에 따라, 시스템의 성격에 따라 다를 수 있다.
중요한 건, 자신만의 소신 있는 기준을 가지고 합리적인 이유로 선택하는 것.
지금의 선택이 반드시 완벽하진 않더라도, 그 판단의 근거를 설명할 수 있다면 그게 바로 좋은 설계라고 생각한다.