Comment utiliser les filtres d’exception Nest.js pour gérer les erreurs



Les mécanismes de filtres d’exceptions dans Nest.js offrent la possibilité d’intercepter et de gérer les erreurs, que ce soit à l’échelle globale de l’application ou au niveau de chaque contrôleur.

Ces filtres permettent une centralisation de la logique de traitement des erreurs, une mise en forme uniforme des réponses d’erreur, et garantissent une gestion cohérente des erreurs dans l’ensemble de votre application. Explorons ensemble les filtres d’exception et leur utilisation pour une gestion optimale des erreurs applicatives.

Gestion des erreurs par défaut dans Nest.js

Par défaut, Nest.js intègre une couche de gestion des exceptions qui prend en charge toutes les erreurs que votre code d’application ne traite pas spécifiquement.

Lorsqu’une erreur non gérée survient, Nest.js la détecte et renvoie une erreur serveur interne 500 au client. La réponse JSON envoyée par Nest.js dans ce cas se présente comme suit :

{
  "statusCode": 500,
  "message": "Internal server error"
}

Si l’objet d’erreur généré par votre code comprend un `statusCode` et un `message`, Nest.js privilégiera ces valeurs à la réponse par défaut.

Pour éviter ce comportement standard et fournir au client des réponses d’erreur plus informatives, une gestion rigoureuse de toutes les erreurs potentielles est nécessaire. Cela peut être accompli grâce aux filtres d’exception intégrés ou personnalisés de Nest.js.

Création d’un filtre d’exception personnalisé

Pour illustrer la création d’un filtre d’exception personnalisé, nous allons en concevoir un qui traitera toutes les exceptions HTTP.

Commençons par un fichier nommé `http.exception.ts` et ajoutons-y les importations suivantes :

import {
    ExceptionFilter,
    Catch,
    ArgumentsHost,
    HttpException,
} from '@nestjs/common';
import { Request, Response } from 'express';

Ces importations ont les rôles suivants :

  • `ExceptionFilter` : Interface définissant l’implémentation d’un filtre d’exception.
  • `Catch` : Décorateur identifiant une classe comme filtre d’exception Nest.
  • `ArgumentsHost` : Interface fournissant des méthodes pour récupérer les arguments passés à un gestionnaire. Permet de sélectionner le contexte d’exécution approprié (par exemple, HTTP, RPC ou WebSockets) pour obtenir les arguments.
  • `HttpException` : Classe définissant l’exception HTTP de base de Nest.
  • `Request` et `Response` : Interfaces pour les objets de requête et de réponse d’Express.js, respectivement.

Ensuite, créez une classe, `HttpExceptionFilter`, qui implémente `ExceptionFilter`. Annotez-la avec le décorateur `Catch` pour indiquer qu’elle gère les `HttpException` :

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {}

Remplissez ensuite la classe avec ce code :

catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response.status(status).json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
        message:
            exception.message
            || exception.getResponse()['message']
            || 'Internal Server Error',
    });
}

Ce code extrait les objets de requête et de réponse de l’objet `ArgumentsHost` et récupère les informations pertinentes de l’exception. Il envoie au client une réponse JSON structurée, contenant des détails sur l’erreur.

Attacher les filtres d’exception

Un filtre d’exception peut être rattaché à un contrôleur spécifique ou à l’ensemble de l’application, selon les besoins.

Pour une liaison globale, importez d’abord le filtre dans votre fichier `main.ts`. Ensuite, passez une instance de votre filtre à la méthode `app.useGlobalFilters` :

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './exception/http.exception';

async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.useGlobalFilters(new HttpExceptionFilter());
    await app.listen(4050);
}
bootstrap();

Pour attacher un filtre à un contrôleur, importez le décorateur `UseFilters` ainsi que votre filtre d’exception. Annotez la classe de votre contrôleur avec le décorateur `@UseFilters`, en lui passant une instance de votre filtre d’exception en argument :

@Controller()
@UseFilters(new HttpExceptionFilter())
export class AppController {}

L’emplacement où vous liez votre filtre détermine la portée de la gestion des erreurs. Les filtres liés à un contrôleur ne s’appliqueront qu’à ce contrôleur, tandis que les filtres liés à l’application s’étendront à l’ensemble de l’application.

Utiliser des exceptions prédéfinies pour signaler les erreurs

Nest.js fournit un ensemble de classes d’exception intégrées que vous pouvez utiliser pour générer des erreurs.

Par exemple, vous pouvez signaler des erreurs de code d’état 404 avec la classe `NotFoundException` :

    getUserById(id: number) {
        const user = users.find((user) => user.id === id);

        if (!user) {
            throw new NotFoundException({
                message: `User with id ${id} not found`,
            });
        }
    }

Ce code vérifie si l’utilisateur spécifié existe. Si ce n’est pas le cas, une erreur 404 est générée en utilisant `NotFoundException`, en passant un message en argument.

Classes d’exceptions intégrées courantes

Voici d’autres classes d’exceptions intégrées :

  • `BadRequestException` : Indique une requête incorrecte avec un code d’état 400. Utilisée lorsque la requête du client est invalide et ne peut être traitée par le serveur.
  • `UnauthorizedException` : Indique un accès non autorisé avec un code d’état 401. Utilisée lorsqu’un utilisateur n’est pas authentifié ou n’a pas les permissions nécessaires pour accéder à une ressource.
  • `ForbiddenException` : Indique un accès interdit avec un code d’état 403. Utilisée lorsqu’un utilisateur authentifié n’est pas autorisé à effectuer une action spécifique.
  • `RequestTimeoutException` : Indique un dépassement du délai de requête avec un code d’état 408. Utilisée lorsqu’un serveur met fin à une requête car son traitement a pris trop de temps.
  • `ConflictException` : Indique un conflit avec un code d’état 409. Utilisée en cas de conflit entre la requête du client et l’état actuel de la ressource.
  • `InternalServerErrorException` : Indique une erreur serveur interne avec un code d’état 500. Utilisée lorsqu’une erreur inattendue se produit côté serveur, empêchant le serveur de traiter la requête.

Bonnes pratiques pour la gestion des erreurs dans Nest.js

Lors de la gestion des erreurs dans Nest.js, il est recommandé d’utiliser des filtres d’exception pour intercepter et gérer les exceptions, soit globalement, soit au niveau des contrôleurs. Vous pouvez également créer des filtres personnalisés pour des types d’exceptions spécifiques.

De plus, l’utilisation des classes d’exception intégrées appropriées est cruciale pour générer des erreurs pertinentes et informatives. Ces pratiques amélioreront considérablement la fiabilité de vos applications Nest.js.