web-dev-qa-db-fra.com

Quelle est l'approche de gestion des erreurs nestjs (erreur de logique métier vs erreur http)?

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:

  1. Avoir des services individuels et des canaux de validation throw new Error(), avoir le contrôleur catch eux et lancer le type approprié de HttpException (BadRequestException, ForbiddenException etc..)
  2. Demandez au contrôleur d'appeler simplement la méthode de canal de service/validation responsable de la gestion de cette partie de la logique métier et de lancer le HttpException approprié.

Les deux approches présentent des avantages et des inconvénients:

  1. Cela semble la bonne façon, cependant, le service peut renvoyer Error pour différentes raisons, comment puis-je savoir à partir du contrôleur quel serait le type correspondant de HttpException à retourner?
  2. Très flexible, mais avoir 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?

7
Aaron Ullal

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 .

2
Kim Kern

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

1
Alexey Petushkov