Gestion des Exceptions dans NestJS
Nest est livré avec une couche d’exception intégrée qui est responsable du traitement de toutes les exceptions non gérées à travers une application. Lorsque qu’une exception n’est pas gérée par votre code d’application, elle est capturée par cette couche qui envoie alors automatiquement une réponse conviviale appropriée.
Par défaut, cette action est effectuée par un filtre d’exception global intégré, qui gère les exceptions de type HttpException
(et ses sous-classes). Lorsque qu’une exception est non reconnue (n’est ni HttpException
ni une classe qui en hérite), le filtre d’exception intégré génère la réponse JSON par défaut suivante :
{ "statusCode": 500, "message": "Internal server error"}
Lancer des exceptions standard
Nest fournit une classe intégrée HttpException
, exposée depuis le paquet @nestjs/common
. Pour les applications API REST/GraphQL HTTP typiques, il est d’usage d’envoyer des objets de réponse HTTP standard lorsque certaines conditions d’erreur se produisent.
Par exemple, dans le CatsController
, nous avons une méthode findAll()
(un gestionnaire de route GET
). Supposons que ce gestionnaire de route lance une exception pour une raison quelconque. Pour démontrer cela, nous allons le coder de la manière suivante :
@Get()async findAll() { throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);}
Lorsque le client appelle ce point de terminaison, la réponse ressemble à ceci :
{ "statusCode": 403, "message": "Forbidden"}
Le constructeur de HttpException
prend deux arguments obligatoires qui déterminent la réponse :
- L’argument
response
définit le corps de la réponse JSON. Il peut s’agir d’unestring
ou d’unobject
comme décrit ci-dessous. - L’argument
status
définit le code de statut HTTP.
Par défaut, le corps de la réponse JSON contient deux propriétés :
statusCode
: par défaut le code de statut HTTP fourni dans l’argumentstatus
.message
: une courte description de l’erreur HTTP en fonction dustatus
.
Exceptions personnalisées
Dans de nombreux cas, vous n’aurez pas besoin d’écrire des exceptions personnalisées et pouvez utiliser l’exception HTTP intégrée de Nest, comme décrit dans la section suivante. Si vous avez besoin de créer des exceptions personnalisées, il est de bonne pratique de créer votre propre hiérarchie d’exceptions, où vos exceptions personnalisées héritent de la classe de base HttpException
. Avec cette approche, Nest reconnaîtra vos exceptions et s’occupera automatiquement des réponses d’erreur. Implémentons une telle exception personnalisée :
export class ForbiddenException extends HttpException { constructor() { super('Forbidden', HttpStatus.FORBIDDEN); }}
Puisque ForbiddenException
hérite de la base HttpException
, elle fonctionnera sans problème avec le gestionnaire d’exceptions intégré, et nous pourrons donc l’utiliser dans la méthode findAll()
:
@Get()async findAll() { throw new ForbiddenException();}
Exceptions HTTP intégrées
Nest fournit un ensemble d’exceptions standard qui héritent de la base HttpException
. Celles-ci sont exposées depuis le paquet @nestjs/common
, et représentent de nombreuses exceptions HTTP les plus courantes :
BadRequestException
UnauthorizedException
NotFoundException
ForbiddenException
NotAcceptableException
RequestTimeoutException
ConflictException
GoneException
HttpVersionNotSupportedException
PayloadTooLargeException
UnsupportedMediaTypeException
UnprocessableEntityException
InternalServerErrorException
NotImplementedException
ImATeapotException
MethodNotAllowedException
BadGatewayException
ServiceUnavailableException
GatewayTimeoutException
PreconditionFailedException
Toutes les exceptions intégrées peuvent également fournir à la fois une cause
d’erreur et une description d’erreur en utilisant le paramètre options
:
throw new BadRequestException('Something bad happened', { cause: new Error(), description: 'Some error description'});
Filtres d’exception
Bien que le filtre d’exception de base (intégré) puisse automatiquement traiter de nombreux cas pour vous, vous souhaiterez peut-être un contrôle total sur la couche d’exceptions. Par exemple, vous pouvez vouloir ajouter la journalisation ou utiliser un schéma JSON différent en fonction de certains facteurs dynamiques. Les filtres d’exception sont conçus pour exactement ce but. Ils vous permettent de contrôler le flux exact de contrôle et le contenu de la réponse renvoyée au client.
Créons un filtre d’exception responsable de la capture des exceptions qui sont une instance de la classe HttpException
, et d’implémenter une logique de réponse personnalisée pour elles. Pour cela, nous devrons accéder aux objets de plateforme sous-jacents Request
et Response
. Nous accéderons à l’objet Request
pour pouvoir extraire l’URL d’origine et l’inclure dans les informations de journalisation. Nous utiliserons l’objet Response
pour prendre le contrôle direct de la réponse envoyée, en utilisant la méthode response.json()
.
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';import { Request, Response } from 'express';
@Catch(HttpException)export class HttpExceptionFilter implements ExceptionFilter { 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, }); }}
Le décorateur @Catch(HttpException)
lie les métadonnées requises au filtre d’exception, indiquant à Nest que ce filtre particulier recherche des exceptions de type HttpException
et rien d’autre. Le décorateur @Catch()
peut prendre un seul paramètre, ou une liste séparée par des virgules. Cela vous permet de configurer le filtre pour plusieurs types d’exceptions à la fois.