모바일 앱과 웹 앱이 동일한 API를 공유하면 어느 한쪽은 항상 필요 이상의 데이터를 받거나, 반대로 여러 번 요청을 보내야 하는 문제가 생긴다. BFF(Backend For Frontend) 는 클라이언트 유형마다 전용 백엔드 레이어를 두어 이 불일치를 해소하는 패턴이다. Sam Newman이 마이크로서비스 문맥에서 정립한 이 패턴은 프론트엔드 팀이 백엔드 인터페이스를 직접 소유할 수 있게 해준다.
API Gateway는 인증, 레이트 리밋, 라우팅 같은 횡단 관심사(cross-cutting concerns)를 단일 진입점에서 처리한다. 클라이언트 종류에 무관하게 동일한 규칙을 적용하는 인프라 레이어다. BFF는 그 위에 놓이는 클라이언트 맞춤형 집계 레이어다.
| 구분 | API Gateway | BFF |
|---|---|---|
| 목적 | 인증·라우팅·보안 | 클라이언트별 응답 최적화 |
| 클라이언트 인식 | 없음 | 있음 (클라이언트마다 별도 존재) |
| 비즈니스 로직 | 없음 | 집계·변환 로직 포함 |
| 소유 팀 | 인프라/플랫폼 | 프론트엔드 팀 |
횡단 관심사(Cross-Cutting Concerns) — 여러 레이어에 걸쳐 공통으로 적용되는 관심사. 인증, 로깅, 트레이싱 등.
┌──────────┐ ┌──────────┐
│ Web App │ │Mobile App│
└────┬─────┘ └────┬─────┘
│ │
┌───────▼──────┐ ┌───────▼──────┐
│ Web BFF │ │ Mobile BFF │
│ (Node.js) │ │ (Node.js) │
└──┬───┬───┬───┘ └──┬───┬───┬──┘
│ │ │ │ │ │
┌─────▼┐ ┌▼──┐ ┌▼────┐ │ │ │
│User │ │Order│ │Product│ (동일 마이크로서비스 호출)
│ SVC │ │ SVC │ │ SVC │
└──────┘ └─────┘ └──────┘
Web BFF는 대시보드에 필요한 주문 목록, 사용자 정보, 추천 상품을 한 번의 요청으로 집계해서 반환한다. Mobile BFF는 네트워크 비용을 줄이기 위해 이미지 URL을 썸네일로 교체하고 불필요한 필드를 제거한다.
BFF의 핵심 역할은 두 가지다.
Aggregation — 여러 마이크로서비스를 병렬 호출하고 결과를 하나로 합친다.
async function getOrderDetailPage(orderId: string) {
const [order, user, products] = await Promise.all([
orderService.getOrder(orderId),
userService.getUser(order.userId),
productService.getProducts(order.productIds),
]);
return { order, user, products };
}
Composition — 클라이언트가 소화하기 좋은 형태로 데이터를 재조합한다. 예를 들어 모바일은 페이지네이션 크기를 10으로, 웹은 50으로 다르게 적용한다.
Aggregation — 분산된 데이터를 하나의 응답으로 묶는 것. Composition — 묶인 데이터를 클라이언트 요구에 맞게 재구성하는 것.
장점
단점
BFF는 클라이언트 종류가 두 개 이상이고, 각 클라이언트의 데이터 요구사항이 뚜렷이 다를 때 도입을 검토할 만하다. 단일 클라이언트라면 API Gateway 수준에서 충분한 경우가 많다.