Beyond a single GET request, real applications need to combine, cache, and cancel API calls correctly. This lesson covers those practical patterns.
Structuring API Calls in a Real App
Real applications rarely make a single, isolated API call. Views often need data from multiple endpoints, need to avoid re-fetching unchanged data, and need to cancel in-flight requests when a component is destroyed before the response arrives.
A clean layering, components call services, services call HttpClient, keeps these concerns manageable as an application grows.
forkJoin runs multiple requests in parallel and emits once, after all of them complete.
combineLatest combines multiple ongoing streams, re-emitting whenever any of them produces a new value.
switchMap chains a dependent second request after the first resolves, and cancels a stale in-flight request if the source emits again.
Choosing the right combinator avoids manual subscription nesting ("callback pyramids").
API Call Patterns Cheatsheet
Common RxJS operators for combining and managing API requests.
Operator/Pattern
Use Case
forkJoin
Run independent requests in parallel, wait for all
switchMap
Chain a dependent request, cancel stale ones automatically
combineLatest
Combine multiple ongoing streams reactively
takeUntilDestroyed()
Automatically unsubscribe when the component is destroyed
shareReplay(1)
Cache and share the latest emitted value among subscribers
catchError
Handle request failures gracefully
Parallel Requests With forkJoin
When a view needs data from multiple independent endpoints at once, forkJoin runs them in parallel and emits a single combined result once every request has completed, rather than waiting for them sequentially.
If a component is destroyed before its API call resolves (the user navigates away quickly), the subscription should be cleaned up to avoid updating a component that no longer exists. takeUntilDestroyed() automates this cleanup.
For data that doesn't change often (like a list of countries or app configuration), shareReplay(1) caches the latest emitted value and shares it with every subscriber, avoiding a repeated network request for data you already have.
takeUntilDestroyed() cleans up in-flight request subscriptions automatically when a component is destroyed.
shareReplay(1) caches and shares a response across multiple subscribers, avoiding redundant network calls.
Keep API composition logic inside services, not scattered across component subscribe callbacks.
Pro Tip
Use takeUntilDestroyed() (from @angular/core/rxjs-interop) by default on any subscription initiated from a component; it eliminates an entire category of memory leak and "updating a destroyed component" bugs with a single operator.
You now understand practical API call patterns. Next, learn about Interceptors for handling cross-cutting HTTP concerns like auth tokens.