Otherwise known as chaining multiple Observables / API.
In the real world scenario, we always face a situation where an id of a data depends on previously emitted value.
To be precise, let’s assume we need to fetch userId using only by username and sequentially fetch all his/her articles or posts using the userId.
The Obvious Approach – Nested Subscription.
this.data.getUserByName('Carley84').subscribe({ next: (value) => { console.log(value); this.data.getArticles(value[0].id).subscribe(a => console.log(a)); this.data.getPosts(value[0].id).subscribe(p => console.log(p)); }, complete: () => console.log('Completes with Success!'), error: (err) => console.log(err), });
The above code is self explanatory, we are making a call to fetch user details and from the response, we are making two other API calls.
Eventually creating a nested subscription, so we can make use of value from our first subscription.
mergeMap
A mergeMap is best fit in this case, since we can get the value of the previous response and pass on to API’s to execute next.
this.data .getUserByName('Carley84') .pipe( map((users) => { const user = users[0]; return user; }), mergeMap(user => { return this.data.getArticleByUser(user.id); }) ) .subscribe({ next: (value) => console.log('Final Value:', value), complete: () => console.log('Completes with Success!'), error: (err) => console.log(err), });
Looking at the above code, the second API getArticleByUser requires a user id to fetch a list of articles by that user. The user Id is from the first Observable.
mergeMap and forkJoin – Multiple API’s
To solve the issue of multiple API requests that depends on the result of another request or previous request, we can use forkJoin inside mergeMap.
// this.data .getUserByName('Carley84') .pipe( map((users) => { const user = users[0]; return user; }), mergeMap(user => { const articles = this.data.getArticleByUser(user.id); const posts = this.data.getPostByUser(user.id); return forkJoin({articles, posts}); }) ) .subscribe({ next: (value) => console.log('Final Value:', value), complete: () => console.log('Completes with Success!'), error: (err) => console.log(err), }); // Output // {articles: Array[2], posts: Array[2]} //
You can find some information about forkJoin in my blog here.
Conclusion
In conclusion, RxJS offers powerful operators to perform multiple API requests by avoiding nested Subscriptions. This certainly helps us to write more maintainable and clean code.