Angular 4에서 RxJS Observable 체이닝 패턴
문제 상황
사용자 정보를 조회한 후, 해당 사용자의 권한 정보를 추가로 가져와야 하는 요구사항이 있었다. 처음에는 subscribe 안에서 또 다시 subscribe를 호출하는 방식으로 구현했는데, 콜백 지옥과 비슷한 구조가 되어버렸다.
해결 방법
RxJS의 고차 매핑 연산자를 사용해서 Observable을 평탄화했다.
getUserWithPermissions(userId: string): Observable<UserWithPermissions> {
return this.http.get<User>(`/api/users/${userId}`)
.switchMap(user =>
this.http.get<Permission[]>(`/api/permissions/${user.id}`)
.map(permissions => ({ ...user, permissions }))
)
.catch(error => Observable.throw(error));
}
switchMap vs mergeMap vs concatMap
- switchMap: 새로운 요청이 들어오면 이전 Observable을 취소한다. 검색 자동완성처럼 최신 요청만 필요한 경우 사용
- mergeMap: 모든 Observable을 동시에 실행한다. 순서가 중요하지 않은 병렬 처리에 적합
- concatMap: Observable을 순차적으로 실행한다. 순서 보장이 필요할 때 사용
현재 케이스는 사용자 정보를 먼저 받아야 권한 조회가 가능하므로 switchMap이 적절했다.
추가 개선
에러 처리를 서비스 레벨에서 일관되게 하기 위해 ErrorHandler를 별도로 분리했다.
private handleError(error: any): Observable<never> {
console.error('API Error:', error);
return Observable.throw(error.message || 'Server error');
}
Angular 4로 업그레이드하면서 HttpClient로 마이그레이션 예정이다. 기존 Http 모듈보다 타입 안정성이 개선된다고 한다.