REST API 무한 호출지옥에서 벗어나는 법 - 시니어들이 실제로 쓰는 API 설계 전략
하나의 화면, 6번의 API 호출
얼마 전 동료가 만든 대시보드를 보다가 무심코 개발자 도구를 열어봤습니다. 사용자 프로필 화면 하나를 그리는데 REST API 호출이 6번 발생하더라고요. 프로필 정보, 권한, 최근 활동, 알림 설정, 구독 상태, 통계 데이터... 각각 따로따로 날아가고 있었습니다.
개별 API는 모두 200ms 안에 응답했어요. 그런데 화면이 다 채워지기까지는 1.5초가 걸렸습니다. 일부 데이터가 다른 API 응답에 의존적이라 순차로 실행될 수밖에 없었거든요. 호출 하나하나는 합격점인데, 합쳐놓으니 느렸습니다.
이게 바로 2015년식 REST API 설계의 전형적인 함정입니다.

REST가 만들어낸 착각
REST가 인기를 끌면서 많은 팀이 착각에 빠졌습니다. '리소스 중심 설계'가 곧 '좋은 API 설계'라고 믿게 된 거죠. 저도 한동안 그렇게 생각했습니다.
새 요구사항이 생기면 새 엔드포인트를 추가하고, 예외 케이스가 생기면 컨트롤러를 하나 더 만들고, 클라이언트가 달라지면 응답 형태를 또 추가하고... 이게 반복됩니다.
코드 리뷰에서는 다 문제없어 보였는데, 막상 제품을 만지면 어딘가 항상 무거운 느낌이었습니다.
원인을 따져보면 결국 하나입니다. 우리가 시스템 설계와 엔드포인트 증가를 혼동했다는 점이요. 엔드포인트를 늘리는 건 설계가 아니라 그냥 면적을 넓히는 일에 가깝습니다. 그러는 사이 클라이언트가 백엔드의 내부 구조를 너무 많이 알아야 하는 상황이 만들어집니다. 어떤 데이터를 어떤 순서로 가져와야 화면이 완성되는지, 그 조립 책임이 슬그머니 프런트로 넘어가는 거죠.
진짜 문제는 '접합 부분'
제가 겪은 가장 답답한 상황은 이런 모양이었습니다.
- 각 서비스의 모니터링 지표는 정상
- 개별 API 응답 시간도 합격점
- 그런데 사용자는 "앱이 느리다"고 한다
부품은 다 멀쩡한데 전체 경험만 엉망인 상황이죠. 운영하면서 이런 패턴을 여러 번 봤습니다. 대시보드 어디를 봐도 빨간불은 없는데, 정작 사용자 체감은 나쁜.
범인은 보통 서비스 자체가 아니라 그 사이의 접합 부분입니다. 한 서비스가 다른 서비스보다 살짝 느리거나, 네트워크가 조금만 흔들려도 화면 전체 로딩이 크게 밀립니다. 순차 호출 구조에서는 가장 느린 한 곳이 전체 속도를 결정하니까요. 그동안 프런트엔드는 화면을 그리는 게 아니라, 백엔드 서비스들과 데이터를 언제 어떤 순서로 받을지 협상하느라 바쁩니다.
시니어들의 다른 접근법
이 패턴을 오래 본 사람들은 질문 자체를 바꿉니다.
"다음 리소스를 어떻게 노출할까?" ❌
"사용자가 실제로 무엇을 하려고 하는가?" ✅
사소해 보이지만, 이 한 줄이 대화의 방향을 통째로 바꿉니다. 리소스 목록을 그리던 머리가 사용자 행동의 흐름을 따라가기 시작하는 거죠. 목적지가 아니라 흐름 관점입니다.
경험 중심 API 설계
그렇게 보면 자연스럽게 이런 구조가 나옵니다.
클라이언트
↓
사용자 액션 하나 → 요청 하나
↓
경험 API (BFF/GraphQL/통합 API)
↓
프로필 서비스, 권한 서비스, 활동 서비스...
↓
화면에 맞춰 구성된 하나의 응답
이 모델의 가치는 호출 횟수를 줄이는 것 그 이상입니다.
- 오케스트레이션을 제어 가능한 위치로 이동: 재시도, fallback, 캐싱, 부분 오류 처리가 전부 서버 안으로 들어옵니다
- 관찰 가능성 향상: 흩어진 호출이 아니라, 사용자 여정 하나가 통합된 경로로 보입니다
- 클라이언트 복잡성 감소: 앱은 데이터 조립 로직 대신 UI에 집중할 수 있습니다
특히 두 번째가 운영 자리에서 크게 와닿았습니다. 호출이 6개로 흩어져 있으면 로그도 6군데에 흩어집니다. 정작 필요한 한 줄은 늘 엉뚱한 곳에 있고요. 흐름을 하나로 묶으면 추적할 지점이 줄어듭니다.
도구는 도구일 뿐
현업에서 쓰이는 선택지를 펼쳐보면 대략 이렇습니다.
| 상황 | 선택하는 기술 | 이유 |
|---|---|---|
| 고정된 화면, 예측 가능한 데이터 | BFF (Backend for Frontend) | 성능 최적화와 캐싱에 유리 |
| 화면이 자주 바뀌고 유연한 쿼리 필요 | GraphQL | 클라이언트가 필요한 데이터만 요청 가능 |
| 서비스 간 통신, 엄격한 계약 | gRPC | 타입 안정성과 성능 |
| 실시간 업데이트 | WebSocket/Server-Sent Events | 폴링은 2026년에 어울리지 않음 |
표를 보면 정답이 하나로 정해져 있지 않다는 게 보입니다. 핵심은 특정 기술에 대한 충성심이 아니거든요. 사용자가 백엔드의 파편화 문제를 직접 떠안지 않게 하는 것, 그 목표만 충족하면 도구는 상황에 맞게 고르면 됩니다.

제가 저질렀던 실수들
솔직히 저도 이 함정에 여러 번 빠졌습니다.
"엔드포인트 하나 더 추가하는 게 제일 빠르고 간단하네?" 이렇게 생각한 적이 많았어요. 그 순간에는 가장 효율적인 선택처럼 느껴졌습니다. 그런데 나중에 보면 결국 복잡성을 클라이언트 쪽으로 떠넘긴 것이었더라고요.
그리고 비용은 항상 이 순서로 돌아왔습니다.
- 사용자가 먼저 부담 (느린 로딩)
- 제품팀이 부담 (사용자 불만)
- 몇 달 뒤 엔지니어링 팀이 부담 (리팩토링)
당장 빠른 선택이 가장 비싼 선택이었던 셈이죠. 엔드포인트를 추가할 때 든 시간보다, 나중에 흩어진 호출을 다시 묶느라 든 시간이 훨씬 길었습니다.
2026년의 현실적인 접근
최근에 본 좋은 백엔드 팀들은 REST, GraphQL, gRPC를 "종교"처럼 떠받들지 않습니다. 도구로 보지, 정체성으로 보지 않아요. 어떤 기술을 쓰느냐로 자기 팀을 정의하지 않는다는 뜻입니다.
그들이 실제로 따지는 기준은 단순합니다.
- 조정 비용 최소화
- 왕복 횟수 감소
- 비즈니스 로직을 오류 관리가 쉬운 곳에 배치
경험이 쌓이면서 분명해지는 게 하나 있습니다. 좋은 API 설계는 모든 걸 깔끔하게 드러내는 게 아니라, 제품이 단순하게 느껴지도록 적절한 복잡성을 안쪽에 숨기는 일이라는 점입니다. 드러낼 것과 감출 것을 나누는 판단, 그게 설계의 본체에 가깝습니다.

마무리
사용자는 서비스가 몇 개인지, 데이터베이스 테이블이 어떻게 쪼개져 있는지 전혀 관심 없습니다. 화면이 빠르고 안정적으로 작동하는지만 봅니다.
만약 어떤 팀의 핵심 기능이 아직도 "클라이언트가 순서를 신중하게 정해야 하는 일련의 REST 호출"에 기대고 있다면, 따져야 할 건 그게 언제 만들어졌느냐가 아닙니다.
진짜 문제는, 시스템이 내부의 혼란을 아키텍처라는 이름으로 포장해서 바깥으로 밀어내고 있다는 점이에요. 그 청구서는 결국 사용자에게, 그다음엔 다시 우리에게 돌아옵니다.