条件に基づいて、オブザーバブルのmap演算子からエラーをスローしたい。たとえば、正しいAPIデータが受信されない場合。次のコードをご覧ください。
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.") );
}
基本的にコードでわかるように、応答(resオブジェクト)に 'bearerToken'がない場合、エラーをスローする必要があります。そのため、私のサブスクリプションでは、後述の2番目のパラメーター(handleError)に入ります。
.subscribe(success, handleError)
助言がありますか?
map()
演算子内でエラーをスローするだけです。 RxJSのすべてのコールバックはtry-catchブロックでラップされているため、キャッチされてerror
通知として送信されます。
つまり、何も返さずにエラーをスローするだけです。
map(res => {
if (res.bearerToken) {
return this.saveJwt(res.bearerToken);
} else {
throw new Error('Valid token not returned');
}
})
throwError()
(RxJS 5の以前のObservable.throw()
)は、error
通知を送信するだけのObservableですが、map()
は何を返すかを気にしません。 map()
からObservableを返した場合でも、next
通知として渡されます。
最後に、おそらく.catchError()
(RxJS 5の以前のcatch()
)を使用する必要はないでしょう。エラーが発生したときに副作用を実行する必要がある場合は、たとえばtap(null, err => console.log(err))
(RxJS 5では以前のdo()
)を使用することをお勧めします。
2019年1月:RxJS 6用に更新
throw new Error()
が観測不可能なように思える場合は、switchMap
を使用できます。
// 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.httpPost.pipe(switchMap(res => (res.bearerToken) ?
of(this.saveJwt(res.bearerToken)) :
throwError('Valid token not returned')
));
動作は同じになり、構文が異なります。
文字通り、パイプ内のhttpオブザーバブルから別のオブザーバブルへの「切り替え」を言います。これは、出力値を単に「ラップ」するか、新しい「エラー」オブザーバブルです。
of
を忘れずに入力すると、わかりにくいエラーメッセージが表示されます。
また、「switchMap」の利点は、saveJwt
を使用して実行する必要があるロジックに対して、まったく新しいコマンドチェーンを返すことができることです。
この質問はすでに回答されていますが、私は自分のアプローチを共有したいと思います(上記とわずかに異なる場合でも)。
マッピングとは別に返されるものを決定し、逆も同様です。どの演算子がこれに最適かわからないので、tap
を使用します。
this.httpPost.pipe(
tap(res => {
if (!res.bearerToken) {
throw new Error('Valid token not returned');
}
}),
map(res => this.saveJwt(res.bearerToken)),
);