API HATEOAS 적용 (자기 설명적, 클라이언트 의존성, 실무 적용)
REST API를 개발하면서도 HATEOAS(Hypermedia as the Engine of Application State)라는 원칙을 제대로 이해하지 못했습니다. 그냥 URI 구조만 신경 쓰면 REST라고 생각했거든요. 그런데 한 프로젝트에서 이걸 직접 적용해보려고 시도했을 때, 이게 생각보다 훨씬 복잡하고 실무에서는 논란이 많은 개념이라는 걸 깨달았습니다. HATEOAS는 API 응답에 다음 행동 가능한 링크를 포함해서 클라이언트가 문서 없이도 API를 탐색할 수 있게 하는 방식인데, 이게 정말 REST의 이상적인 구현일까요, 아니면 불필요한 복잡성을 추가하는 걸까요?
자기 설명적 API 구조의 이상과 현실
HATEOAS를 적용하면 API 응답이 자기 설명적(Self-Descriptive)이 됩니다. 쉽게 말해 서버가 보내는 응답 안에 "다음에 뭘 할 수 있는지" 정보가 모두 들어있다는 뜻입니다. 예를 들어 주문 정보를 조회했을 때, 응답에 "결제하기", "취소하기", "배송 조회" 같은 링크가 함께 포함되는 거죠. 이론적으로는 클라이언트 개발자가 API 문서를 일일이 찾아보지 않아도, 서버가 제공하는 링크만 따라가면 모든 기능을 사용할 수 있습니다.
이걸 구현해봤을 때 느낀 건, 설계 단계에서는 정말 멋진 아이디어처럼 보였다는 겁니다. 각 리소스마다 가능한 액션을 링크로 제공하니까 API 구조가 명확해 보였거든요. 그런데 막상 응답 구조를 짜다 보니 데이터보다 링크 정보가 더 많아지는 상황이 발생했습니다. 단순한 사용자 정보 조회 API에서도 관련 링크를 여러 개 포함하다 보니 JSON 응답이 복잡해졌고, 프론트엔드 팀에서는 이걸 파싱하는 로직이 오히려 번거롭다는 피드백을 주었습니다.
REST 아키텍처의 창시자인 로이 필딩(Roy Fielding)은 HATEOAS가 없으면 진정한 REST API가 아니라고 주장했습니다(출처: Roy Fielding's Blog). 하지만 상용 서비스를 보면 GitHub API, Twitter API 같은 유명한 REST API들도 HATEOAS를 완전히 적용하지 않는 경우가 많습니다. 이상적인 원칙과 현실적인 개발 효율성 사이에서 어떤 선택을 해야 할까요?
클라이언트 의존성 감소와 구현 복잡도의 딜레마
HATEOAS를 지지하는 분들은 클라이언트와 서버의 결합도(Coupling)를 낮출 수 있다고 강조합니다. 여기서 결합도란 두 시스템이 서로 얼마나 의존하는지를 나타내는 지표로, 결합도가 낮을수록 한쪽을 수정해도 다른 쪽에 영향을 덜 줍니다. 예를 들어 서버에서 API 경로를 변경해도 클라이언트는 서버가 제공하는 링크만 따라가면 되니까, 이론적으로는 클라이언트 코드를 수정하지 않아도 됩니다.
이건 정말 매력적인 장점처럼 들렸습니다. 초기 설계 회의에서 팀원들과 "나중에 API 버전 관리가 편해지겠다"며 기대했거든요. 하지만 구현하면서 몇 가지 문제가 드러났습니다. 먼저 프론트엔드에서 동적으로 링크를 해석하는 로직을 작성해야 했는데, 이게 생각보다 복잡했습니다. 특정 상황에서 어떤 링크가 나타날지 예측하기 어려웠고, 예외 처리도 까다로웠습니다.
또 HATEOAS를 제대로 활용하려면 클라이언트가 "링크 기반 네비게이션"을 지원해야 하는데, 일반적인 웹이나 앱 개발 방식과는 좀 다른 접근이 필요했습니다. 결국 저희 팀은 다음과 같이 절충안을 선택했습니다:
- 핵심 비즈니스 플로우(주문-결제-배송)에만 HATEOAS 적용
- 단순 조회 API는 기존 방식 유지
- 링크 정보는 선택적으로 포함(클라이언트가 필요할 때만 사용)
모든 API에 일괄 적용하는 건 비효율적이었습니다. 서비스 특성에 따라 선택적으로 도입하는 게 현실적인 접근이라고 생각합니다.
실무 적용에서의 한계와 선택적 도입 전략
대부분의 상용 API에서 HATEOAS를 완전히 적용하지 않는 데는 이유가 있습니다. 여러 프로젝트를 경험하면서 느낀 건, HATEOAS가 빛을 발하는 경우는 상당히 제한적이라는 겁니다. 특히 CRUD(Create, Read, Update, Delete) 중심의 단순한 API에서는 HATEOAS의 장점이 거의 체감되지 않았습니다. 사용자 목록을 가져오는 API에 굳이 다음 페이지 링크, 상세 조회 링크, 수정 링크를 모두 포함할 필요가 있을까요?
반면 복잡한 워크플로우를 가진 시스템에서는 유용할 수 있습니다. 제가 참여했던 프로젝트 중 전자결재 시스템이 있었는데, 문서의 상태(작성중, 결재중, 승인, 반려)에 따라 가능한 액션이 계속 바뀌었습니다. 이런 경우 서버가 현재 상태에서 가능한 액션 링크를 제공하면 클라이언트 로직이 훨씬 단순해졌습니다. 일반적으로 HATEOAS는 상태 기반 플로우가 복잡한 도메인에 적합하다고 알려져 있습니다.
실무에서 HATEOAS를 도입하려면 다음을 고려해야 합니다. 첫째, 팀의 개발 역량과 학습 비용입니다. HATEOAS는 개념 자체가 생소하기 때문에 팀원들이 이해하고 활용하는 데 시간이 걸립니다. 둘째, API 응답 크기 증가입니다. 링크 정보가 추가되면서 네트워크 트래픽이 늘어날 수 있습니다. 특히 모바일 환경에서는 부담이 될 수 있습니다. 셋째, 기존 시스템과의 호환성입니다. 이미 운영 중인 API에 HATEOAS를 추가하려면 클라이언트도 함께 수정해야 하는데, 이게 쉽지 않습니다.
개인적으로는 HATEOAS를 "선택적으로" 도입하는 게 가장 현실적이라고 봅니다. 모든 API에 일괄 적용하기보다는, 정말 필요한 부분(복잡한 워크플로우, 자주 변경되는 비즈니스 로직)에만 적용하는 거죠. REST의 이상적인 원칙을 따르되, 실무에서의 효율성도 함께 고려하는 균형 잡힌 접근이 필요합니다.
결국 HATEOAS는 "반드시 적용해야 하는 규칙"이 아니라 "상황에 따라 선택하는 도구"라고 생각합니다. 여러 번 시행착오를 겪으면서 내린 결론은, 이상적인 아키텍처 원칙보다 서비스 환경에서 팀이 효율적으로 개발하고 유지보수할 수 있는 구조가 더 중요하다는 것입니다. 만약 여러분 팀에서 HATEOAS 도입을 고민 중이라면, 먼저 작은 범위에서 시범 적용해보고 실제 효과를 측정해보시길 권합니다. 이론과 실무 사이의 간극을 직접 경험해보는 게 가장 확실한 판단 기준이 될 겁니다.
댓글
댓글 쓰기