observable'の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())はObservableであり、
error通知を送信するだけであるが、
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 observableから別のobservableに'switch'と言っているのです。
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)),
);