Reputation: 2625
I have a service which interacts with an api server. It has myHttpPost(data) method. This method should:
The current version of my method is:
postData(path: string, data: Object): Rx.Observable<any> {
let json = JSON.stringify(data);
return this.http.post(path, json)
.map(res => res.json())
}
This is not doing point 3 from the above list, because map is only called upon success and not on error. I could change the sequence by adding:
.catch(error => {
let myError = prepareErrorContent(error);
return Rx.Observable.throw(myError);
});
Then the subscriber (another service) receives myError (that's ok) but the rxjs documentation says the following about catch() method: "Continues an observable sequence that is terminated by an exception with the next observable sequence." But I want the sequence to terminate normally and not to continue. If I use the catch()
like above, then the next call to postData() from the subscriber does not work (it immediately returns the same error instead of making the http call). I think it's because the sequence is not terminated.
How to do it?
[Edit] This is my subscriber method which uses this service:
this.jsonHttp.postData(path, data)
.subscribe(
struct => onNext(struct),
error => {
let message = this.jsonHttp.extractError(error);
onError(message)
},
() => onComplete ? onComplete() : null
);
Upvotes: 11
Views: 21200
Reputation: 202138
In fact, for each HTTP request a processing chain is created and executed. When the response is received (both successful and with error), the chain is completed.
If you execute twice the request, there is no link between them. You can have some links when both requests are part of the same processing chain. For example when using observable operators like flatMap
or switchMap
. Here is a sample:
return this.http.get(...)
.map(res => res.json())
.flatMap(jsonData => {
// Can leverage the result of the previous request
return this.http.get(...).map(res => res.json());
});
When an error occurs, the processing chain is broken and the catch
operator is called. You can return an observable in the associated callback to continue the processing chain. It can be a classical observable or an error one with Observable.throw
. In the context of an HTTP request in Angular2, a response with a status code different than 2xx is considered as an error.
When returning Observable.throw
, the second callback specified when subscribed is called. If it's another observable, the first callback is called. For example:
return this.http.get(...)
.map(res => res.json())
.catch(res => {
// The error callback (second parameter) is called
return Observable.throw(res.json());
// The success callback (first parameter) is called
// return Observable.of(res.json());
});
I implemented a plunkr that execute a request (clicking on a button) without authentication header, so a 401 status code is received. When you click again, the header is added, so a 200 status code is received. Just to show you that there is no relation between the two requests.
See this plunkr: https://plnkr.co/edit/5WwWpwjvQmJ4AlncKVio?p=preview.
Upvotes: 18