How to throw error from RxJS map operator (angular)

Hassan picture Hassan · Apr 4, 2017 · Viewed 80.9k times · Source

I want to throw an error from my observable's map operator based on a condition. For instance if correct API data is not received. Please see the following code:

private userAuthenticate( email: string, password: string ) {
    return this.httpPost(`${this.baseApiUrl}/auth?format=json&provider=login`, {userName: email, password: password})
        .map( res => { 
            if ( res.bearerToken ) {
                return this.saveJwt(res.bearerToken); 
            } else {
                // THIS DOESN'T THROW ERROR --------------------
                return Observable.throw('Valid token not returned');
            }
        })
        .catch( err => Observable.throw(this.logError(err) )
        .finally( () => console.log("Authentication done.") );
}

Basically as you can see in the code, if the response (res object) doesn't have 'bearerToken' i want to throw out an error. So that in my subscription it goes into the 2nd parameter (handleError) mentioned below.

.subscribe(success, handleError)

Any suggestions?

Answer

martin picture martin · Apr 4, 2017

Just throw the error inside the map() operator. All callbacks in RxJS are wrapped with try-catch blocks so it'll be caught and then sent as an error notification.

This means you don't return anything and just throw the error:

map(res => { 
  if (res.bearerToken) {
    return this.saveJwt(res.bearerToken); 
  } else {
    throw new Error('Valid token not returned');
  }
})

The throwError() (former Observable.throw() in RxJS 5) is an Observable that just sends an error notification but map() doesn't care what you return. Even if you return an Observable from map() it'll be passed as next notification.

Last thing, you probably don't need to use .catchError() (former catch() in RxJS 5). If you need to perform any side effects when an error happens it's better to use tap(null, err => console.log(err)) (former do() in RxJS 5) for example.

Jan 2019: Updated for RxJS 6