I got 3 endpoints that returns upcoming, current, past events. I should show only the one that is the farthest in the future. To optimize the calls and not to call all the endpoints at once.I have written a simple RxJs stream where I call the first endpoint and if it does not return data I call second and so on. The code looks like this:
this.eventsService.getUpcoming(id).pipe(
switchMap((upcoming) => {
if (upcoming.length) {
return of(upcoming);
}
return this.eventsService.getCurrent(id).pipe(
switchMap((current) => {
if (current.length) {
return of(current);
}
return this.eventsService.getPast(id)
})
);
}),
// some other pipe operators map etc.
It is possible not to have nested switch map within a switch map?
I think you could use just concat()
to make the calls sequential and then take(1)
and skipWhile()
to automatically complete when the first useful response arrives:
concat(
this.eventsService.getUpcoming(id),
this.eventsService.getCurrent(id),
this.eventsService.getPast(id)
).pipe(
skipWhile(response => response.length === 0),
defaultIfEmpty([]),
take(1),
);
take(1)
will complete the chain when the first item in skipWhile
doesn't match the condition.
Try something like this
this.eventsService.getUpcoming(id).pipe(
switchMap((upcoming) => {
if (upcoming.length) {
return of(upcoming);
}
return this.eventsService.getCurrent(id)
},
switchMap((current) => {
if (current.length) {
return of(current);
}
return this.eventsService.getPast(id)
})
)
This way you do not nest the switchMap
You can use concat operator to create an observable which sequentially emits values from each observable. Pipe the results to the find operator that will return the result from the first result that meets the condition and complete the observable. This will prevent subsequent observables to be executed from the stream created by concat.
Difference between first and take
One side effect of find that I think you will find useful for your example is that if no conditions are met, then the last result is still emitted. This is different then using an operator like first which will throw an error if the source observable completes without a match, or take which won't emit anything since a prior operator would be used for filtering emissions.
So in your case you'll at least get an empty array if all responses are empty.
concat(
// try each request in order.
this.eventsService.getUpcoming(id),
this.eventsService.getCurrent(id),
this.eventsService.getPast(id)
).pipe(
// emits the first result that meets the condition.
find(response => response.length > 0)
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With