Angular http request observable error does not catch error?
Asked Answered
R

1

7

Angular 6 using HttpClient. No interceptors implemented for now.

I have an admin service where I'm doing a http call to MSGraph. In this case I'm getting an error 400 bad request which I'm sending to the notification handler.

I've slided in that console.log to make sure that the error block is firing at all and another cnosole.log to see if the 'data' getting back from the server is an error.

None of the console.logs fire yet the global error handler still displays the 400 bad request response in the console.

I'd like to be able to use this response and display a user-friendly message.

Code:

this.http.get(this.GRAPH_ROOT_URL + this.APP_ID, { headers }).subscribe(data => {
  this.notification.done(data);
  console.log(data);
}), error => {
  this.notification.error(`Error getting users from Microsoft GRAPH API. Reason: ${error}`)
  console.log("this is observable error", error);
}
Rack answered 11/10, 2018 at 10:21 Comment(5)
Which version of Angular?Boost
Sorry, Angular6 -- forgot to add!Rack
add one more param to subscribe - the complete callback and console.log therePulsate
@Pulsate would it be possible to elaborate on this? Not entirely sure how that param would look like.Rack
i meant normal callback: () => console.log('Completed'). Subscribe function takes 3 params - success, error and complete, these are all callbacks so you pass some function there, just like the functions you pass for success and error. My idea was that the complete callback was called.Pulsate
B
8

Angular 6 uses RxJS 6, which comes with a number of changes. Assuming that's what you're using, this is what I would use:

Here's what I would use:

this.http.get(this.GRAPH_ROOT_URL + this.APP_ID, { headers })
    .pipe(catchError(err => {
      this.alert.error('There was an error getting data');
      return throwError(err);
    })).subscribe(data => this.notification.done(data));

So you use pipe to call catchError, which does handle the server errors correctly.

To use catchError, you need to import it first, like this:

import { catchError } from 'rxjs/operators';
Boost answered 11/10, 2018 at 10:28 Comment(9)
Just tried this -- the only problem is the .pipe(catchError part -- the catchError is not defined/available from anywhere. I was able to import the throwError one from rxjs. I am indeed using RxJS6 -- not the latest version as that brings breaking changes to a lot of things that I'm using. But still RxJS6Rack
Thanks! This works exactly as intended. Kinda bummed I have to refactor 20+ http requests now, should've tested this a lot sooner! The only problem is now when I try to write the err object on the service it shows up as [object object]; I'm suspecting this is because of the order I'm doing things in and will tweak it a bit.Rack
@Rack While you're going to invest the time, go a step further and wrap HttpClient in a service of your own. It really makes this kind of thing simpler and gives you additional options. For example, my actual code also includes automatic retry for GET and visual notifications for success or failure.Boost
Is there any chance you have that example somewhere on github that I could take a look? I am wrapping everything in a service, it's just that I've got 4 services with observables in 2 apps that I'm working at the moment, almost all of them with a redux architecture. If I manage to do it right at the service level, it'll be an absolute breeze to then consume them in components.Rack
Sorry, no. My service basically has the same Get, Post, etc. functions, but adds pipe calls for catchError and retry (for Get only). It also calls the notification service, which seems similar to yours. The point is just that it gives you options and you can expand at will. I also have certain overloads that automatically place single objects in arrays and so on. You could probably do much of it with interceptors as well, but I would always wrap it.Boost
I understand, my only question is on the 'retry' logic. Is that purely in the case of a timeout or is there other benefits to retrying the GET request? Btw thanks a lot for your help so far, this has been very valuable to me.Rack
Aha. That's a simple .pipe(retry(2)) added just before my pipe for catchError. So it makes a maximum of three attempts and only then returns the error. retry is imported from the same module as catchError.Boost
hah! that would be very valuable, can't believe I haven't thought of that! Thanks for all man. Good luck!Rack
This doesn't work. BadRequest response still throws an exception in the browser but never hits the code.Harem

© 2022 - 2024 — McMap. All rights reserved.