Handling HTTP request in an Angular application is a crucial part. In this article we will go through below methods from RxJs to handle HTTP requests.
- map → applies the function supplied to each value of input observable and emits the resulting value as observable.
- mergeMap or flatMap → allows us to flatten multiple separate subscribed Observable into a single cohesive stream, which we can use to control events coming from user input and from server responses.
- switchMap → Projects each source value to an Observable which is merged in the output Observable, emitting values only from the most recently projected Observable.
- forkJoin → Accepts an Array of
ObservableInputor a dictionary
ObservableInputand returns an
Observablethat emits either an array of values in the exact same order as the passed array, or a dictionary of values in the same shape as the passed dictionary.
Use case: One use case could be we want to convert all observables into observables of JSON objects.
signature: map<T, R>(project: (value: T, index: number) => R, thisArg?: any): OperatorFunction<T, R>
As shown in Example when we want to return the result from service as json so map function is applying the logic on the input observable and returns the json as observable.
Pros: As it helps in applying project function on the input observable and emits them as observable, it helps in modifying the response data in desired manner.
mergeMap or flatMap
Signature: mergeMap<T, R, O extends ObservableInput<any>>(project: (value: T, index: number) => O, resultSelector?: number | ((outerValue: T, innerValue: ObservedValueOf<O>, outerIndex: number, innerIndex: number) => R), concurrent: number = Number.POSITIVE_INFINITY): OperatorFunction<T, ObservedValueOf<O> | R>
Use Case: When we want to access the value of one subscribed observable into another, we can use the mergeMap to pass it and get the a single cohesive stream we can use to control events.
Example: Say you want to do call 2 HTTP request sequentially where we are passing value of one to another. Lets try to use mergeMap for the same.
Pros: We can Make HTTP request sequentially dynamically.
Cons: It doesn't cancels the previously called observable subscription which could cause the mix-up of the responses.
Note that flatMap flattens a stream of observable (i.e observable of observables) to a stream of emitted values (a simple observable), by emitting on the "trunk" stream everything that will be emitted on "branch" streams.
switchMap is very similar to flatMap, but with a very important distinction. Any events to be merged into the trunk stream are ignored if a new event comes in.
Signature: switchMap<T, R, O extends ObservableInput<any>>(project: (value: T, index: number) => O, resultSelector?: (outerValue: T, innerValue: ObservedValueOf<O>, outerIndex: number, innerIndex: number) => R): OperatorFunction<T, ObservedValueOf<O> | R>
Use Case: Let’s say we wanted to implement a server based search feature in which every keypress in a text field will automatically perform a search and update the page with the results. How would this look? Well we would have an observable subscribed to events coming from an input field, and on every change of input we want to perform some HTTP request, which is also an observable we subscribe to. What we end up with is an observable of an observable.
Say we use flatMap for this. Service will look like below
OK, let’s take a look at the component that will be using this service.
We have one issue here if the server, for some reason, takes a very long time to respond to a particular query. If we use flatMap, we run the risk of getting results back from the server in the wrong order. Let's illustrate this with an example.
Consider a situation in the example where we first type in the letters Tabl, and suppose the string Tabl is actually a special string where it will take the server a few extra seconds to reply.
Meanwhile, after we paused for a bit (more than the debounce time), we decide to type in another letter (the letter e) and our app sends a request to the server for the string Table. Since Table is not considered a special string, the server replies very quickly and our app sets the suggestions for Table.
A few seconds later, however, the server finally replies with the response for the Tabl string, and our app receives that response and sets the search suggestions for Tabl, overwriting the suggestions for the Table string, even though the request for that actually came afterwards.
We can solve this using switchMap. Updated component code for swithMap
This implementation of incremental search with switchMap is more robust than the one we saw on the previous page with flatMap as the old trunk of Tabl is ignored when the call is made with Table so that user will always see the last thing user typed. Thanks to this, we can guarantee a great user experience regardless of how the server responds.
Pros: As the old trunk is ignored we have a great user experience regardless of the server response.
Cons: As the old trunk is ignored in case of multiple parallel calls will overwritten with the last one.
forkJoin help us to do multiple http calls in parallel and waits for them to resolve.
forkJoin will wait for all the request to resolve and group all the observables returned by each HTTP call into a single observable array and finally returns the same.
signature: forkJoin(…args, selector : function): Observable
In example above we have done 2 HTTP calls, the same way can be used for desired number of calls.
We can subscribe the response as shown in the above example.
Pros: With forkJoin we can join observables from different HTTP calls and respond as one observable array.
Cons: If any of the inner observables supplied to
forkJoin error you will lose the value of any other observables that would or have already completed. We can avoid this with catching error properly in inner observable.
If you liked this article, please 👏 below, so that other people can find it! :D