Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does HTTP error-handling work with observables?

I see a lot of tutorials doing something like this:

http.get("...").subscribe(
  success => console.log('hello success'),
  error => console.log('bye error')
);

I don't know how this works, since there aren't any types or anything, however I tried to do that myself and I end up that the request always goes into success, even if I have an error. What is the problem?

Troublemaker:

this.memberService.create(this.currentMember)
      .subscribe(
        success => {
          let mem: Member = success.json() as Member;
          if (this.selectedOrganization) {
            this.addMemberToOrganization(mem);
          } else if (this.selectedServiceProvider) {
            this.addMemberToServiceProvider(mem);
          } else {
            this.toastsService.error("lbl_users_service_provider_and_organization_undefined");
          }
        },
        error => console.log(error)
      );

Create-Method in the memberService:

  create(member: Member): Observable<any> {
    return this.http
      .post(this.RESOURCE_BASE_URL, member)
      .map(response => {
        if (response.status === 200) this.toastsSerivce.success(this.translateService.instant('lbl_users_member_created'));
        return response;
      })
      .catch(error => this.toastsSerivce.error(this.translateService.instant('lbl_users_member_create_failed')));
  }

I even catch the error, but the subscribe part doesn't seem to care. It fails at success.json(), because if there is an error, there is no json. But if there is an error, I want it to call the error =>... instead of the success. Any advice is highly appreciated.

like image 676
codepleb Avatar asked Jun 06 '17 09:06

codepleb


People also ask

How do you perform error handling in observables?

Catch errors in the observable stream 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.

How does Angular handle HTTP errors?

When the error occurs in the HTTP Request it is intercepted and invokes the catchError . Inside the catchError you can handle the error and then use throwError to throw it to the service. We then register the Interceptor in the Providers array of the root module using the injection token HTTP_INTERCEPTORS .

Does observable complete after error?

The Observable Contract and Error Handling Network requests can fail, for example. A stream can also complete, which means that: the stream has ended its lifecycle without any error. after completion, the stream will not emit any further values.

How do you perform error handling for HttpClient Angular?

The basic way to handle errors in Angular is to use Angular's HttpClient service along with RxJS operators throwError and catchError. The HTTP request is made, and it returns the data with a response if anything wrong happens then it returns an error object with an error status code.


2 Answers

I think the issue is that you are not throwing the error with an Observable.throw(errMsg).

So, you may just use it like this:

.catch((error:any) => Observable.throw(error.json().error || 'Server error')); 

In your example:

create(member: Member): Observable<any> {     return this.http       .post(this.RESOURCE_BASE_URL, member)       .map(response => {         if (response.status === 200) this.toastsSerivce.success(this.translateService.instant('lbl_users_member_created'));         return response;       })       .catch((error:any) => Observable.throw(this.toastsSerivce.error(this.translateService.instant('lbl_users_member_create_failed'))));   } 

But, you could use an error handler, like the one Angular proposes here:

private handleError (error: Response | any) {     // In a real world app, you might use a remote logging infrastructure     let errMsg: string;     if (error instanceof Response) {       const body = error.json() || '';       const err = body.error || JSON.stringify(body);       errMsg = `${error.status} - ${error.statusText || ''} ${err}`;     } else {       errMsg = error.message ? error.message : error.toString();     }     console.error(errMsg);     return Observable.throw(errMsg);   } 

And so, your method would look more like this:

create(member: Member): Observable<any> {     return this.http       .post(this.RESOURCE_BASE_URL, member)       .map(response => {         if (response.status === 200) this.toastsSerivce.success(this.translateService.instant('lbl_users_member_created'));         return response;       })       .catch(this.handleError);   } 

It's actually cleaner and more reusable for other methods that you may create within your service.

I would suggest to use also a response handler, like the one used by Angular's devs: this.extractData.

Obviusly, inside the error handle method you can put your own custom logic, depends on how you want to show or handle the error.

NOTE: I did not test your code nor the code I posted here. But I wanted to show/express the concept. You should throw the error in order to not going into success everytime. How you handle it depends on you and your App.

like image 118
SrAxi Avatar answered Oct 14 '22 04:10

SrAxi


It works for me:

this.http.post('http://example.com/path/', {sampleData: 'd'}).subscribe(
  res => {alert('ok!');},
  err => {alert(err.error)}
)
like image 38
yaya Avatar answered Oct 14 '22 03:10

yaya