Reputation: 233
I'm building a small Angular app as part of my training. I'm trying to implement an error interceptor based on what is shown in the Angular tutorial. The idea is that I want to handle the error and then return an observable so that my components still receive data.
Interceptor:
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { ToastrService } from 'ngx-toastr';
@Injectable({
providedIn: 'root'
})
export class ErrorInterceptor implements HttpInterceptor {
constructor(private toastr: ToastrService) { }
private handleError<T> (result?: T) {
return (error: any): Observable<T> => {
// Log the error on the console.
console.log(error);
// Display user friendly message.
this.toastr.error(`${error.error.message}`, `${error.statusText}:`);
// Let the app keep running by returning an empty result.
console.log(result);
return of(result as T);
};
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next
.handle(request)
.pipe(
catchError(this.handleError<any>({data: {token: 'asd'}}))
);
}
}
Service:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { Subscription, Observable, of, throwError } from 'rxjs';
import { tap, map, catchError } from 'rxjs/operators';
import { LoginInput } from '../models/login.input-model';
import { RegisterInput } from '../models/register.input-model';
import { ServerResponse } from '../../../core/models/server-response.model';
import { ToastrService } from 'ngx-toastr';
const root = '/api/';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private loginUrl: string = root + 'auth/login';
private registerUrl: string = root + 'auth/signup';
private login$: Subscription;
private register$: Subscription;
constructor(
private http: HttpClient,
private router: Router,
private toastr: ToastrService) { }
private saveToken(data) {
localStorage.setItem('token', data.token);
}
login(payload: LoginInput): void {
this.login$ = this.http
.post<ServerResponse>(this.loginUrl, payload)
.subscribe((loginData) => {
console.log('loginData: ' + loginData);
// this.router.navigate(['/home']);
});
}
clearLoginSubscription() {
if (this.login$) this.login$.unsubscribe();
}
}
Expected behaviour: The interceptor handles the error and returns the result as an observable. The data is then emitted on subscribe. Actual behaviour: The interceptor handles the error and nothing else happens. No data is emitted on login/register subscribe.
Note: I have discovered that if I migrate the handleError function to the service and pipe it in the same way that I have in the interceptor. I do get the expected behaviour. It just doesn't work from the interceptor.
Upvotes: 1
Views: 1476
Reputation: 21
For those who want to handle the error and then progagate it, just implement the The Catch and Rethrow Strategy.
Your handleError function must throw the error:
return throwError(result);
This way, your component can receive data but in the error callback, not in the success callback of subscribe().
Reference: https://blog.angular-university.io/rxjs-error-handling/
Upvotes: 0
Reputation: 7231
You can capture data as :
this.http
.post<ServerResponse>(this.loginUrl, payload)
.subscribe((loginData) => {
console.log('loginData: ' + loginData);
// this.router.navigate(['/home']);
}, (err: HttpErrorReponse) => {
console.log(err);
};
http-intercepter.ts
/**
*
* @param req - parameter to handle http request
* @param next - parameter for http handler
*/
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const started = Date.now();
/**
* Handle newly created request with updated header (if given)
*/
return next.handle(req).do((event: HttpEvent<any>) => {
/**
* Sucessfull Http Response Time.
*/
if (event instanceof HttpResponse) {
const elapsed = Date.now() - started;
}
}, (err: any) => {
/**
* redirect to the error_handler route according to error status or error_code
* or show a modal
*/
if (err instanceof HttpErrorResponse) {
console.log(err)
}
});
}
Upvotes: 1