node.js - Nestjs class-validator undantag - hur man kastar metadata information för @IsNotIn validator
Jag har en NestJs dto som ser ut så här
import { IsEmail, IsNotEmpty, IsNotIn } from 'class-validator';
import { AppService } from './app.service';
const restrictedNames = ['Name Inc', 'Acme Inc'];
class DTO {
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
@IsNotEmpty()
@IsNotIn(restrictedNames)
orgName: string;
}
Jag använder ett undantagsfilter som returnerar fel med tydliga detaljer om vilken validering som misslyckades och för vilket fält.
app.useGlobalPipes(
new ValidationPipe({
exceptionFactory: (validationErrors: ValidationError[] = []) => {
console.log(validationErrors);
return new BadRequestException({
statusCode: HttpStatus.BAD_REQUEST,
message: validationErrors.reduce((acc, error) => {
acc[error.property] = Object.keys(error.constraints).map(
(failed) => ({
failedValidation: failed,
message: error.constraints[failed],
}),
);
return acc;
}, {}),
error: 'validation',
});
},
}),
);
vilket returnerar ett fel som ser ut ungefär så här
{"statusCode":400,"message":{"email":[{"failedValidation":"isEmail","message":"email must be an email"}],"orgName":[{"failedValidation":"isNotIn","message":"orgName should not be one of the following values: Name Inc, Acme Inc"}]},"error":"validation"}
Men för den misslyckade valideringen som @NotIn skulle jag vilja att felet var mer specifikt när det gäller vilka som är reserverade nyckelord, och vill att de returneras i felet som en separat nyckel som:
{"statusCode":400,"message":{"email":[{"failedValidation":"isEmail","message":"email must be an email"}],"orgName":[{"failedValidation":"isNotIn","message":"orgName should not be one of the following values: Name Inc, Acme Inc", "data":{"reservedKeywords":["Name Inc","Acme Inc"]}}]},"error":"validation"}
Men detta block från undantagsfiltret returnerar inte begränsningsvärdena med dekoratormetadatan.
message: validationErrors.reduce((acc, error) => {
acc[error.property] = Object.keys(error.constraints).map(
(failed) => ({
failedValidation: failed,
message: error.constraints[failed],
}),
);
return acc;
}, {}),
error: 'validation',
});
Svar #1
Enligt min kunskap finns det inget koncept för att automatiskt returnera metadata eller liknande. Eftersom du lagrar de svartlistade värdena i variablerna kan du tillhandahålla det som context, vilket är mappat till särskilda feltyper.
const restrictedNames = ['Name Inc', 'Acme Inc'] as const;
class DTO {
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
@IsNotEmpty()
@IsNotIn(restrictedNames, { context: { reservedKeywords: restrictedNames } }) // here
orgName: string;
// You may ignore the contructor
constructor(name: string, email: string, orgName: string) {
this.name = name;
this.email = email;
this.orgName = orgName;
}
}
Nu behöver du bara inkludera värdet villkorligt i din transformfunktion med error.contexts
const transformedMessage = errors.reduce((acc, error) => {
acc[error.property] = Object.keys(error.constraints).map((failed) => ({
failedValidation: failed,
message: error.constraints[failed],
data: error.contexts && error.contexts[failed],
}));
return acc;
}, {});
Som du vill, här är resultatet.
{
"email": [
{
"failedValidation": "isEmail",
"message": "email must be an email"
}
],
"orgName": [
{
"failedValidation": "isNotIn",
"message": "orgName should not be one of the following values: Name Inc, Acme Inc",
"data": {
"reservedKeywords": [
"Name Inc",
"Acme Inc"
]
}
}
]
}
PS: Tack för att du tillhandahöll transformfunktionen. Jag stjäl den skamlöst.
