To ensure an error doesn't complete the outer observable, a common rxjs effects pattern I've adopted is:
public saySomething$: Observable<Action> = createEffect(() => {
return this.actions.pipe(
ofType<AppActions.SaySomething>(AppActions.SAY_SOMETHING),
// Switch to the result of the inner observable.
switchMap((action) => {
// This service could fail.
return this.service.saySomething(action.payload).pipe(
// Return `null` to keep the outer observable alive!
catchError((error) => {
// What can I do with error here?
return of(null);
})
)
}),
// The result could be null because something could go wrong.
tap((result: Result | null) => {
if (result) {
// Do something with the result!
}
}),
// Update the store state.
map((result: Result | null) => {
if (result) {
return new AppActions.SaySomethingSuccess(result);
}
// It would be nice if I had access the **error** here.
return new AppActions.SaySomethingFail();
}));
});
Notice that I'm using catchError
on the inner observable to keep the outer observable alive if the underlying network call fails (service.saySomething(action.payload)
):
catchError((error) => {
// What can I do with error here?
return of(null);
})
The subsequent tap
and map
operators accommodate this in their signatures by allowing null
, i.e. (result: Result | null)
. However, I lose the error information. Ultimately when the final map
method returns new AppActions.SaySomethingFail();
I have lost any information about the error.
How can I keep the error information throughout the pipe rather than losing it at the point it's caught?