class-validator总结

461 阅读4分钟

class-validator提供了声明式的数据完整性断言方法。它利用装饰器(decorators),帮助您快速定义数据验证的规则。

什么是class-validator

class-validator是一个TypeScript库,它允许使用装饰器或非装饰器基础的验证。它依赖于validator.js,这是一个字符串验证和清洗的库。它可以用在浏览器和Node.js环境下。

安装

使用npm安装class-validator

npm install class-validator --save

在 TypeScript 项目中,需要确保启用了装饰器:

// tsconfig.json
{
  "experimentalDecorators": true,
  "emitDecoratorMetadata": true
}

基础用法

使用class-validator时,只需在类属性上添加验证装饰器:

import { IsInt, Min, Length, validate } from 'class-validator';

class Book {
    @Length(10, 20)
    title: string;

    @IsInt()
    @Min(0)
    rating: number;
}

let book = new Book();
book.title = '短标题'; // 验证错误,标题太短
book.rating = -1; // 验证错误,评分低于最低限制

validate(book).then(errors => {
    if (errors.length > 0) {
        console.log('验证失败:', errors);
    } else {
        console.log('验证通过');
    }
});

class-validator 提供了一系列的装饰器来实现各种验证规则。以下是一些常见的验证装饰器及其用法示例:

验证规则

  1. 基本验证
  • @IsDefined(): 验证属性值是否已定义(不为null或undefined)。

    class Profile {
        @IsDefined()
        name: string;
    }
    

    **

  • @IsEmpty(): 验证属性值是否为空。

    class Profile {
        @IsEmpty()
        middleName: string;
    }
    
  • @IsNotEmpty(): 验证属性值是否不为空。

    class Profile {
        @IsNotEmpty()
        lastName: string;
    }
    
  1. 类型验证
  • @IsBoolean(): 验证属性值是否为布尔值。

    class Product {
        @IsBoolean()
        isActive: boolean;
    }
    
  • @IsString(): 验证属性值是否为字符串。

    class Product {
        @IsString()
        name: string;
    }
    
  • @IsNumber(): 验证属性值是否为数字。

    class Product {
        @IsNumber()
        price: number;
    }
    
  • @IsDate(): 验证属性值是否为日期对象。

    class Appointment {
        @IsDate()
        date: Date;
    }
    
  1. 字符串验证
  • @IsEmail(): 验证属性值是否为有效电子邮件地址。

    class User {
        @IsEmail()
        email: string;
    }
    
  • @IsFQDN(): 验证属性值是否为完全合格的域名。

    class Website {
        @IsFQDN()
        domain: string;
    }
    
  • @IsPhoneNumber(): 验证属性值是否为有效电话号码。

    class User {
        // 传入地区代码来验证不同国家的电话号码格式
        @IsPhoneNumber('CN')
        phone: string;
    }
    
  1. 长度验证
  • @Length(min, max): 验证字符串长度。

    class User {
        @Length(10, 20)
        username: string;
    }
    
  • @MinLength(): 验证字符串最小长度。

    class User {
        @MinLength(10)
        password: string;
    }
    
  • @MaxLength(): 验证字符串最大长度。

    class User {
        @MaxLength(100)
        biography: string;
    }
    
  1. 数值验证
  • @Min(): 验证数值最小值。

    class Rating {
        @Min(0)
        score: number;
    }
    
  • @Max(): 验证数值最大值。

    class Rating {
        @Max(10)
        score: number;
    }
    
  1. 数组验证
  • @ArrayNotEmpty(): 验证数组是否不为空。

    class User {
        @ArrayNotEmpty()
        friends: string[];
    }
    
  • @ArrayMinSize(min): 验证数组最小长度。

    class User {
        @ArrayMinSize(1)
        siblings: string[];
    }
    
  • @ArrayMaxSize(max): 验证数组最大长度。

    class User {
        @ArrayMaxSize(5)
        topMovies: string[];
    }
    
  1. 复杂类型验证
  • @IsInstance(): 验证是否为类的实例。

    class User {
        @IsInstance(Profile)
        profile: Profile;
    }
    
  • @ValidateNested(): 验证嵌套对象。

    class User {
        @ValidateNested()
        profile: Profile;
    }
    
  1. 自定义验证
  • @CustomValidation(): 应用自定义验证规则。

    import { ValidatorConstraint, ValidatorConstraintInterface, registerDecorator, ValidationArguments } from 'class-validator';
    
    @ValidatorConstraint({ name: "customText", async: false })
    export class CustomTextLength implements ValidatorConstraintInterface {
        validate(text: string, args: ValidationArguments) {
            // 自定义验证逻辑
        }
    
        defaultMessage(args: ValidationArguments) {
            // 自定义违规信息
        }
    }
    

class-validator 提供的验证器非常丰富,以上只是一小部分。在实际开发中,可以根据具体需求选择合适的验证器。更多的验证器及详细用法可以在class-validator的GitHub页面查看。

高级用法

分组

您可以选择性地分组应用验证规则:

import { Min, validate } from 'class-validator';

class UserProfile {
    @Min(13, { groups: ['registration'] })
    age: number;
}

validate(userProfile, { groups: ['registration'] }).then(errors => {
    // 处理验证结果
});

自定义验证器

通过扩展ValidatorConstraintInterface定义自定义验证逻辑:

import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, registerDecorator } from 'class-validator';

@ValidatorConstraint({ async: true })
export class IsLongerThanConstraint implements ValidatorConstraintInterface {
    validate(text: string, validationArguments: ValidationArguments) {
        return text.length > validationArguments.constraints[0].length;
    }
}

function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
    return function (object: any, propertyName: string) {
        registerDecorator({
            target: object.constructor,
            propertyName: propertyName,
            options: validationOptions,
            constraints: [property],
            validator: IsLongerThanConstraint,
        });
    };
}

class User {
    @IsLongerThan("nickname")
    fullName: string;

    nickname: string;
}

// 用法略

白名单

自动从对象中去除没有注解的属性:

validate(obj, { whitelist: true }).then(errors => {
    // 处理验证结果
});

忽略缺失属性

只验证对象中存在的属性:

validate(obj, { skipMissingProperties: true }).then(errors => {
    // 处理验证结果
});

自定义消息

自定义消息允许您指定发生特定验证错误时的输出信息。在装饰器中指定message属性可以定制错误消息。

例如:

import { IsInt, Min, validate } from 'class-validator';

class Product {
    @IsInt({
        message: '产品数量必须是一个整数'
    })
    quantity: number;

    @Min(1, {
        message: '产品数量必须大于等于1'
    })
    quantity: number;
}

let product = new Product();
product.quantity = 0.5;

validate(product).then(errors => {
    if (errors.length > 0) {
        console.log('验证失败:', errors.map(error => error.constraints));
    }
});

错误处理

错误处理是验证过程的一部分。class-validator返回一个ValidationError数组,其中包含有关验证错误的详细信息。

例如:

import { Length, validate } from 'class-validator';

class User {
    @Length(10, 20, {
        message: '用户名的长度必须在$constraint1到$constraint2之间,但实际长度为$value'
    })
    username: string;
}

let user = new User();
user.username = 'ana';

validate(user).then(errors => {
    if (errors.length > 0) {
        console.error('验证失败:');
        errors.forEach(error => {
            console.error(`属性 ${error.property}: ${error.constraints?.length}`);
        });
    } else {
        console.log('验证通过');
    }
});

其他提示

其中一些有用的提示包括条件验证和数组验证。使用@ValidateIf()装饰器可以实现条件性验证,而{ each: true }选项用于数组中每个元素的验证。

条件验证示例:

import { ValidateIf, IsNotEmpty, validate } from 'class-validator';

class Post {
    title: string;
    
    @ValidateIf(o => o.title) // 只有当title属性存在时,才会验证text属性
    @IsNotEmpty({
        message: '当标题存在时,文本不能为空'
    })
    text: string;
}

let post = new Post();
post.text = '';

validate(post).then(errors => {
    // 错误:当标题存在时,文本不能为空
});

数组验证示例:

import { ArrayMinSize, IsInt, validate } from 'class-validator';

class Movie {
    @ArrayMinSize(1, {
        message: '至少需要一名演员'
    })
    @IsInt({ each: true, message: '演员ID必须是整数' })
    actorIds: number[];
}

let movie = new Movie();
movie.actorIds = [];

validate(movie).then(errors => {
    // 错误:至少需要一名演员
});