Nest框架自定义验证装饰器实现困惑及问题求助
Hey there! Let me break down how to build a clean, reusable required validation decorator for your NestJS project—this will fix your DRY issue and make sure those null values don't sneak into your database anymore.
First, let's address why your earlier attempts might not have worked: custom validators in Nest rely on class-validator and proper configuration of Nest's ValidationPipe to trigger. If the pipe isn't set up to check custom decorators, or your validator didn't explicitly handle null/undefined values, it would skip validation entirely.
Here's the step-by-step solution:
1. Create a Custom Validator Class
First, we'll build a validator that checks for null, undefined, and empty strings (adjust this logic if you need different rules):
// src/common/validators/required.validator.ts import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator'; @ValidatorConstraint({ name: 'required', async: false }) export class RequiredValidator implements ValidatorConstraintInterface { validate(value: any, args: ValidationArguments) { // Check if value is null, undefined, or an empty/whitespace-only string return value !== null && value !== undefined && (typeof value !== 'string' || value.trim() !== ''); } defaultMessage(args: ValidationArguments) { // Automatically use the field name in the error message return `${args.property} is required.`; } }
2. Wrap It in a Reusable Decorator
Next, we'll create a decorator that registers our validator so we can use it with a simple @Required() annotation:
// src/common/decorators/required.decorator.ts import { registerDecorator, ValidationOptions } from 'class-validator'; import { RequiredValidator } from '../validators/required.validator'; export function Required(validationOptions?: ValidationOptions) { return function (target: Object, propertyName: string) { registerDecorator({ target: target.constructor, propertyName: propertyName, options: validationOptions, validator: RequiredValidator, }); }; }
3. Ensure Your Validation Pipe Is Configured Correctly
For custom decorators to work, your global ValidationPipe needs to enable custom decorator validation. Update your main.ts:
async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true, validateCustomDecorators: true, // Critical for custom validators to trigger })); await app.listen(3000); } bootstrap();
4. Use the Decorator in Your Entity/DTO
Now you can replace your repetitive validation code with a single decorator. No more passing field names manually!
// In your entity class import { Required } from '../common/decorators/required.decorator'; import { Column, DataType } from 'typeorm'; // ... @Required() @Column({ type: DataType.STRING, nullable: false }) // Add nullable: false for DB-level safety zip_code: string;
Bonus: Double Down on Safety
Adding nullable: false to your @Column decorator gives you an extra layer of protection at the database level, so even if validation fails for some reason, the database will reject the null value.
This approach is way cleaner than your current required function—no more repeating field names, and it's fully reusable across all your entities and DTOs.
内容的提问来源于stack exchange,提问作者r0ulito

