Cas d’usage
Un cas d’utilisation courant pour intercepter les erreurs d’une API dans Angular est la gestion centralisée des erreurs HTTP. L’intercepteur peut capturer toutes les erreurs retournées par les requêtes HTTP vers l’API et effectuer des actions en fonction du type d’erreur ou de la réponse du serveur
Comment ca fonctionne ?
Le fonctionnement d’un interceptor est très simple. Voici un schéma qui devrait vous aider à comprendre :
L’interceptor va tout simplement intercepter les requêtes qui transitent entre le client et le serveur. On va donc pouvoir définir ou non des actions lors de l’interception des requêtes.
Comment faire ?
1 – Créer votre interceptor
Pour créer votre Interceptor, vous pouvez utiliser Angular CLI :
$ ng generate interceptor http-error
Une fois votre fichier créé, il devrait ressembler plus ou moins à ca :
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request);
}
}
2 – Intercepter les erreurs des requêtes HTTP
Actuellement votre interceptor détecte toute les requêtes HTTP passante et sortante. Nous on veut détecter les erreurs renvoyées par l’API.
Pour ce faire, nous allons devoir utiliser un opérateur Rxjs : catchError()
. Cet opérateur va catcher (attraper) les erreurs au sein d’un Observable et les retourner.
Commencons déjà par importer catchError()
:
import { catchError } from 'rxjs/operators';
Maintenant qu’il est importer, utilisons le dans notre fonction intercept:
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
return throwError(() => error);
})
);
}
💡
pipe()
permet d’ouvrir une pipeline d’opération, et d’utiliser des opérateurs RxJS.
💡throwError()
créer un Observable d’erreur.
3 – Réagir aux erreurs
Maintenant que nous interceptons nos erreurs renvoyées par notre API, nous pouvons y réagir. Le cas le plus frequent est d’afficher un toast de l’erreur en question :
Dans mon cas j’utilise angular2-notifications
, mais le fonctionnement restera globalement le même avec d’autres packages.
Donc, je l’importe :
import { NotificationsService } from 'angular2-notifications';
Je l’injecte :
constructor(public notifications: NotificationsService) {}
Et maintenant j’affiche mon toast d’erreur :
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
this.notifications.error(error.error.message);
return throwError(() => error);
})
);
}
⚠️ Mon API renvoie un Objet avec l’attribut message qui contient l’erreur en question. Il vous faudra adapter cette partie en fonction des retours de votre API.
4 – Déclarer l’interceptor
Maintenant que l’interceptor est terminé, il faut le déclarer. Pour ce faire, il faudra vous rendre dans le module ou vous souhaiter l’utiliser et importer votre interceptor et HTTP_INTERCEPTORS
et le déclarer :
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpErrorInterceptor } from '@core/interceptors/http-error.interceptor';
@NgModule({
...
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HttpErrorInterceptor,
multi: true
}
]
...
})
💡
multi: true
permet d’ajouter l’interceptor au tableau d’interceptor, plutôt que de les remplacer.
Comment bypass l’interceptor ?
Si pour une raison particulière vous ne voulez pas que l’interceptor intercèpte certaines requêtes, vous pouvez le bypass en utilisant le module httpBackend
.
💡 Les interceptor se situent entre l’interface HttpClient et HttpBackend. L’astuce est donc que nous devons injecter HttpBackend directement dans notre service et créer un nouveau HttpClient en utilisant HttpBackend
Pour commencer il faut importer le module HttpBackend
dans votre service en question :
import { HttpBackend } from '@angular/common/http';
Ensuite, injecter le, et déclarer le :
constructor(
private handler: HttpBackend,
) {
this.httpClient = new HttpClient(handler);
}
Maintenant, quand on utilise this.httpClient
les requêtes ne passerons pas par l’interceptor.
Exemple :
constructor(
private handler: HttpBackend,
) {
this.httpClient = new HttpClient(handler);
}
getUsers(): Observable<User[]> {
return this.httpClient.get<User[]>('/api/users');
}
Si getUsers()
renvoie une erreur, elle ne sera pas intercepté par l’interceptor.