I am trying to validate json request in my nestjs app using my custom validation pipe class "SchemaValidationPipe" which throws BadRequestException. My global exception filter is not catching the exception thrown from validation pipe.
If I throw exception from controller class then global exception filter is able to catch the exception.
@Injectable()
export class SchemaValidationPipe implements PipeTransform<any> {
constructor(private schema: any) {}
transform(value: any, metadata: ArgumentMetadata) {
const schemaValidator = new JsonValidator(this.schema);
schemaValidator
.validate(value)
.then((data) => {
if (data) {
const { isValid, message } = data;
if(!isValid) throw new BadRequestException( { status : '500', message : 'Validation failed' } );
}
return Promise.resolve(value);
})
.catch((err) => {
throw new BadRequestException('Validation failed');
});
}
}
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter<HttpException> {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
I am able to solve to problem by making transform method as async in SchemaValidationPipe class
@Injectable()
export class SchemaValidationPipe implements PipeTransform<any> {
constructor(private schema: any) {}
async transform(value: any, metadata: ArgumentMetadata) {
const schemaValidator = new JsonValidator(this.schema);
try {
const { isValid, message } = await schemaValidator.validate(value);
if(!isValid) throw new BadRequestException( 'Validation failed' );
} catch (err) {
throw new BadRequestException('Validation failed');
}
}
}
Looks like you don't return the provide from the validate
method, so it's considered void. This means that the promise will run outside of the bound request lifecycle and can end up throwing an unhandled provide rejection. You should just need to add return schemaValidator.validate...