web-dev-qa-db-fra.com

Nestjs à jeter de ExceptionFilter

J'essaie d'utiliser un ExceptionFilter pour mapper des exceptions à leur contrepartie HTTP.

Ceci est mon code:

@Catch(EntityNotFoundError)
export class EntityNotFoundFilter implements ExceptionFilter {
    catch(exception: EntityNotFoundError, _Host: ArgumentsHost) {
        throw new NotFoundException(exception.message);
    }
}

Mais, lorsque le code de filtre est exécuté, j'ai reçu un UnhandledPromiseRejectionWarning

 (node:3065) UnhandledPromiseRejectionWarning: Error: [object Object]
    at EntityNotFoundFilter.catch ([...]/errors.ts:32:15)
    at ExceptionsHandler.invokeCustomFilters ([...]/node_modules/@nestjs/core/exceptions/exceptions-handler.js:49:26)
     at ExceptionsHandler.next ([...]/node_modules/@nestjs/core/exceptions/exceptions-handler.js:13:18)
     at [...]/node_modules/@nestjs/core/router/router-proxy.js:12:35
     at <anonymous>
     at process._tickCallback (internal/process/next_tick.js:182:7)
 (node:3065) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 5)

Comment puis-je réparer cela ?

8
Varkal

Le ExceptionFilter est toujours le dernier endroit qui est appelé avant qu'une réponse soit envoyée, il est responsable de la construction de la réponse. Vous ne pouvez pas réthorner une exception de l'intermédiaire d'un ExceptionFilter.

@Catch(EntityNotFoundError)
export class EntityNotFoundFilter implements ExceptionFilter {
  catch(exception: EntityNotFoundError, Host: ArgumentsHost) {
    const response = Host.switchToHttp().getResponse();
      response.status(404).json({ message: exception.message });
  }
}

Sinon, 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;
        }
      }));
  }
}

Essayez-le dans ce codesandbox .

5
Kim Kern

Base sur la solution Kim Kern que j'ai créé cette classe abstraite

export abstract class AbstractErrorInterceptor<T> implements NestInterceptor {
    protected interceptedType: new (...args) => T;

    intercept(
        context: ExecutionContext,
        call$: Observable<any>,
    ): Observable<any> | Promise<Observable<any>> {
        return call$.pipe(
            catchError(exception => {
                if (exception instanceof this.interceptedType) {
                    this.handleError(exception);
                }
                throw exception;
            }),
        );
    }

    abstract handleError(exception: T);
}

Et certaines implémentations

export class EntityNotFoundFilter extends AbstractErrorInterceptor<EntityNotFoundError> {
    interceptedType = EntityNotFoundError;

    handleError(exception: EntityNotFoundError) {
        throw new NotFoundException(exception.message);
    }
}
2
Varkal