Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Angular2, how to intercept error response from observable and pass it to the error channel

Tags:

angular

rxjs

I have a service which interacts with an api server. It has myHttpPost(data) method. This method should:

  1. call Angular's http.post to the server
  2. if response has status 200, provide the response's json content to subscriber
  3. if response has different status, process the response and provide processed error to the subscriber

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
    );
like image 899
camcam Avatar asked Apr 08 '16 09:04

camcam


People also ask

Does observable complete on error?

Bookmark this question. Show activity on this post. When I create an observable from scratch, and have the observer error, then complete, the done part of the subscription never is invoked.

How do you handle errors in Mergemap?

You'll need to use retry or retryWhen (names are pretty self-explanatory) — these operators will retry a failed subscription (resubscribe to the source observable, once an error is emitted.

Which RxJS operator can be chained to an observable to handle errors?

The catchError operator takes as input an Observable that might error out, and starts emitting the values of the input Observable in its output Observable.

How do you catch an error on observable?

Another option to catch errors is to use the CatchError Operator. The CatchError Operators catches the error in the observable stream as and when the error happens. This allows us to retry the failed observable or use a replacement observable.


1 Answers

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.

like image 68
Thierry Templier Avatar answered Sep 27 '22 21:09

Thierry Templier