OnError
Let's get started by creating a badly behaved observable that always throws an exception:
(defn exceptional-obs [] (rx/observable* (fn [observer] (rx/on-next observer (throw (Exception. "Oops. Something went wrong"))) (rx/on-completed observer))))
Now, let's watch what happens if we subscribe to it:
(rx/subscribe (->> (exceptional-obs) (rx/map inc)) (fn [v] (prn-to-repl "result is " v))) ;; Exception Oops. Something went wrong rx-playground.core/exceptional-obs/fn--1505
The exception thrown by exceptional-obs isn't caught anywhere, so it simply bubbles up to the REPL. If this was a web application, our users would be presented with a web server error such as the HTTP code 500 - Internal Server Error. Those users would probably not use our system again.
Ideally, we would like to get a chance to handle this exception gracefully, possibly rendering a friendly error message that will let ours users know we care about them.
As we saw earlier in this chapter, the subscribe function can take up to three functions as arguments:
- The first, the onNext handler, is called when the observable emits a new value
- The second, onError, is called whenever the observable throws an exception
- The third and final function, onComplete, is called when the observable has completed and will not emit any new items
For our purposes, we are interested in the onError handler, and using it is straightforward:
(rx/subscribe (->> (exceptional-obs) (rx/map inc)) (fn [v] (prn-to-repl "result is " v)) (fn [e] (prn-to-repl "error is " e))) ;; "error is " #<Exception java.lang.Exception: Oops. Something went wrong>
This time, instead of throwing the exception, our error handler gets called with it. This gives us the opportunity to display an appropriate message to our users.