Quiero arrojar un error del operador de mapa de mi observable en función de una condición. Por ejemplo, si no se reciben los datos API correctos. Por favor vea el siguiente código:
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.") ); } Básicamente, como puede ver en el código, si la respuesta (objeto res ) no tiene bearerToken , quiero arrojar un error. De modo que en mi suscripción entra en el segundo parámetro ( handleError ) mencionado a continuación.
.subscribe(success, handleError)¿Alguna sugerencia?
Simplemente arroja el error dentro del operador map() . Todas las devoluciones de llamada en RxJS se envuelven con bloques de captura de prueba para que se capturen y luego se envíen como una notificación de error .
Esto significa que no devuelve nada y simplemente arroja el error:
map(res => { if (res.bearerToken) { return this.saveJwt(res.bearerToken); } else { throw new Error('Valid token not returned'); } }) throwError() (anteriormente Observable.throw() en RxJS 5) es un Observable que solo envía una notificación de error pero a map() no le importa lo que devuelves. Incluso si devuelve un Observable desde el map() , se pasará como la next notificación.
Lo último, probablemente no necesite usar .catchError() (antiguo catch() en RxJS 5). Si necesita realizar algún efecto secundario cuando ocurre un error, es mejor usar tap(null, err => console.log(err)) (anteriormente do() en RxJS 5), por ejemplo.
Enero de 2019: actualizado para RxJS 6
Si siente que throw new Error() parece no observable, puede usar return throwError(...) con switchMap en lugar de map (la diferencia es que switchMap tiene que devolver un nuevo observable en lugar de un valor sin procesar):
// this is the import needed for throwError() import { throwError } from 'rxjs'; // RxJS 6+ syntax this.httpPost.pipe(switchMap(res => { if (res.bearerToken) { return of(this.saveJwt(res.bearerToken)); } else { return throwError('Valid token not returned'); // this is } });o más concisamente:
this.httpPost.pipe(switchMap(res => (res.bearerToken) ? of(this.saveJwt(res.bearerToken)) : throwError('Valid token not returned') ));El comportamiento será el mismo, es solo una sintaxis diferente.
Literalmente está diciendo 'cambiar' del observable HTTP en la canalización a un observable diferente, que es simplemente 'envolver' el valor de salida o un nuevo observable de 'error'.
No olvide apagar o recibirá algunos mensajes of error confusos.
Además, la belleza de 'switchMap' es que puede devolver una 'cadena' de comandos completamente nueva si lo desea, para cualquier lógica que deba hacerse con saveJwt .
Aunque esta pregunta ya está respondida, me gustaría compartir mi propio enfoque (aunque solo es ligeramente diferente al anterior).
Yo decidiría qué se devuelve por separado del mapeo y viceversa. No estoy seguro de qué operador es mejor para esto, así que usaré tap .
this.httpPost.pipe( tap(res => { if (!res.bearerToken) { throw new Error('Valid token not returned'); } }), map(res => this.saveJwt(res.bearerToken)), );