javascript - NestJs - Capturando errores de MongoDB con un filtro personalizado y @Catch(MongoError)
Estoy usando NestJS para crear una API personalizada con MongoDB. Tengo la siguiente configuración:
// users.controller.ts
@Post('sign-up')
@UseFilters(MongoExceptionFilter)
async signUp(@Body() createUserDto: CreateUserDto): Promise<any> {
return await this.userService.signUp(createUserDto).catch(error => {
throw new BadRequestException(error);
});
}
// user.service.ts
async signUp(createUserDto: CreateUserDto): Promise<User> {
const createUser = new this.userModel(createUserDto);
return await createUser.save();
}
// mongo-exception.filter.ts
import { ArgumentsHost,Catch, ConflictException, ExceptionFilter } from '@nestjs/common';
import { MongoError } from 'mongodb';
@Catch(MongoError)
export class MongoExceptionFilter implements ExceptionFilter {
catch(exception: MongoError, host: ArgumentsHost) {
console.log('>>>>>>>>>>>>>>>>>>>> exception: ', exception);
}
}
// package.json
"dependencies": {
"@nestjs/common": "^5.4.0",
"@nestjs/core": "^5.4.0",
"@nestjs/jwt": "^0.2.1",
"@nestjs/mongoose": "^5.2.2",
"@nestjs/passport": "^5.1.0",
"@nestjs/typeorm": "^5.2.2",
"fancy-log": "^1.3.3",
"mongoose": "^5.4.7",
"nestjs-config": "^1.3.0",
"passport": "^0.4.0",
"passport-http-bearer": "^1.0.1",
"passport-jwt": "^4.0.0",
"reflect-metadata": "^0.1.12",
"rimraf": "^2.6.2",
"rxjs": "^6.2.2",
"typeorm": "^0.2.12",
"typescript": "^3.0.1",
"util": "^0.11.1"
},
Ahora, cada vez que haga una llamada POST a la ruta /sign-up, save() debería ser llamado en el user.service.ts. Todo esto funciona. Luego, cuando hago POST nuevamente a la ruta /sign-up, debería producir un error de MongoDB ya que el usuario con la misma dirección de correo electrónico ya existe (la dirección de correo electrónico es única y, por lo tanto, las claves duplicadas). Veo que el error se lanza cuando solo registro el error en el .catch(err => ...);, pero el problema es el MongoExceptionFilter personalizado. No se activa en el MongoError. Cuando dejo el @Catch() en blanco, sí se activa, pero no puede procesar la excepción.
¿Qué estoy haciendo mal? Desde que vi esta publicación y la usé como base, no parece que pueda hacerlo funcionar. ¿Es una actualización de Mongoose o NestJS por la que esto ya no funciona?
Respuesta #1
Esto se debe a que conviertes todos los errores en BadRequestExceptions para que tu MongoExceptionFilter no sea responsable; verifica instanceof MongoError que devuelve falso para un BadRequestException:
return await this.userService.signUp(createUserDto).catch(error => {
throw new BadRequestException(error);
});
Esto ocurre antes de que se ejecuten los filtros de excepción; siempre se ejecutan al final.
Elimina .catch() de tu controlador. Si realmente quieres transformar todas las demás excepciones en BadRequestExceptions (400), entonces puedes escribir un segundo filtro de excepciones, que procese todas las excepciones no manejadas por el MongoExceptionFilter:
@Catch()
export class BadRequestFilter implements ExceptionFilter {
catch(exception: Error, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse();
response.status(400).json({message: exception.message});
}
}
y
@Catch(MongoError)
export class MongoFilter implements ExceptionFilter {
catch(exception: MongoError, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse();
if (exception.code === 11000) {
response.status(400).json({ message: 'User already exists.' });
} else {
response.status(500).json({ message: 'Internal error.' });
}
}
}
Luego agrega ambos a tu controlador (¡el orden es importante!):
@UseFilters(BadRequestFilter, MongoFilter)
async signUp(@Body() createUserDto: CreateUserDto): Promise<any> {
