En utilisant NestJS pour créer des API, je me demandais quelle était la meilleure façon de gérer les erreurs/exceptions. J'ai trouvé deux approches différentes:
throw new Error()
, avoir le contrôleur catch
eux et lancer le type approprié de HttpException
(BadRequestException
, ForbiddenException
etc..)HttpException
approprié.Les deux approches présentent des avantages et des inconvénients:
Error
pour différentes raisons, comment puis-je savoir à partir du contrôleur quel serait le type correspondant de HttpException
à retourner?Http
des choses liées dans les services semble tout simplement faux.Je me demandais, lequel (le cas échéant) est la façon de faire "nest js"?
Comment gérez-vous cette affaire?
Supposons que votre logique métier génère un EntityNotFoundError
et que vous souhaitez le mapper sur un NotFoundException
.
Pour cela, vous pouvez créer un Interceptor
qui transforme vos erreurs:
@Injectable()
export class NotFoundInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// next.handle() is an Observable of the controller's result value
return next.handle()
.pipe(catchError(error => {
if (error instanceof EntityNotFoundError) {
throw new NotFoundException(error.message);
} else {
throw error;
}
}));
}
}
Vous pouvez ensuite l'utiliser en ajoutant @UseInterceptors(NotFoundInterceptor)
à la classe ou aux méthodes de votre contrôleur; ou même comme intercepteur global pour toutes les routes. Bien sûr, vous pouvez également mapper plusieurs erreurs dans un seul intercepteur.
Essayez-le dans ce codesandbox .
Vous pouvez souhaiter lier des services non seulement à l'interface HTTP, mais également à GraphQL ou à toute autre interface. Il est donc préférable de convertir les exceptions de niveau logique métier des services en exceptions de niveau Http (BadRequestException, ForbiddenException) dans les contrôleurs.
De la manière la plus simple, cela pourrait ressembler
import { BadRequestException, Injectable } from '@nestjs/common';
@Injectable()
export class HttpHelperService {
async transformExceptions(action: Promise<any>): Promise<any> {
try {
return await action;
} catch (error) {
if (error.name === 'QueryFailedError') {
if (/^duplicate key value violates unique constraint/.test(error.message)) {
throw new BadRequestException(error.detail);
} else if (/violates foreign key constraint/.test(error.message)) {
throw new BadRequestException(error.detail);
} else {
throw error;
}
} else {
throw error;
}
}
}
}
puis