NestJS 中与数据库进行自定义验证
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
NestJS 是一个出色的 Web 框架,它原生支持 TypeScript。其维护者和社区提供了详尽的文档,引导我们逐步了解框架最重要的部分。
但是,当你开始为严肃的应用编写应用程序时,你会很快发现,它无法涵盖一些非常典型的情况(至少对我来说是这样)。
框架提供了多种验证请求数据的方法。我们可以使用管道(Pipes )、基于模式的验证(使用joi 库)或通过集成类验证器库ValidatorPipe。最后一种方法是我最喜欢的。为什么呢?主要原因是您可以将所有验证定义放在控制器之外。这是一种很好的分离不同关注点的方法。
Class-Validator 库是一个强大的工具,它提供了一整套差异化验证装饰器,例如`@validate` @Length(10, 20)、@IsInt()`@ @Contains('example')expression` 等。我不会介绍如何在 NestJS 中使用基本验证,文档对此解释得非常清楚。
但如果您想创建自己的验证器,并将其与 class-validator 库一起使用呢?很简单,只需快速浏览一下文档,您就可以编写自己的规则并将其与@Validate()装饰器一起使用。更棒的是!编写自己的装饰器并使其包含整个请求验证类非常简单。
当我们需要检查持久存储(例如数据库)中的某些内容时,问题就出现了。简而言之,我们必须注入一些负责与数据库交互的依赖项。例如,某个依赖项UserRepository显然负责用户实体。
幸运的是,class-validator它提供了一个非常方便的useContainer功能,允许设置库要使用的class-validor容器。
所以,请将以下代码添加到您的 main.ts 文件中(app变量是您的 Nest 应用程序实例):
useContainer(app.select(AppModule), { fallbackOnErrors: true });
它允许class-validator使用 NestJS 依赖注入容器。
然后我们可以创建一个存储库,该存储库将查询我们的数据库:
@Injectable()
class UserRepository {
async getOneOrFail(userId: number): Promise<UserEntity> {
// some code which fetch user entity or throw exception
}
}
好的,我们来编写一个Validator Constraint用于存放我们自己的验证逻辑的类。正如你所看到的,我们的依赖项只是简单地注入到类构造函数中:
@ValidatorConstraint({ name: 'UserExists', async: true })
@Injectable()
export class UserExistsRule implements ValidatorConstraintInterface {
constructor(private usersRepository: UsersRepository) {}
async validate(value: number) {
try {
await this.usersRepository.getOneOrFail(value);
} catch (e) {
return false;
}
return true;
}
defaultMessage(args: ValidationArguments) {
return `User doesn't exist`;
}
}
别忘了在相应的模块中将可注入类声明为提供者。
现在您可以使用自定义验证约束了。只需使用@Validate(UserExistsRule)装饰器修饰类属性即可:
export class User {
@IsInt()
@Validate(UserExistsRule);
readonly id: number;
}
如果数据库中不存在该用户,您应该会收到默认错误信息“用户不存在”。虽然使用默认的验证器@Validate()已经足够好用,但您也可以编写自己的装饰器,这样会更方便。编写验证器约束非常快捷方便,我们只需要编写一个带有registerDecorator()函数的装饰器工厂即可。
export function UserExists(validationOptions?: ValidationOptions) {
return function (object: any, propertyName: string) {
registerDecorator({
name: 'UserExists',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: UserExistsRule,
});
};
}
如您所见,您可以编写新的验证器逻辑,或者使用之前编写的验证器约束(在我们的例子中是 UserExistsRule类)。
现在我们可以回到我们的User类中,使用@UserExists验证器而不是@Validate(UserExistsRule)装饰器。
export class User {
@IsInt()
@UserExists();
readonly id: number;
}
希望这篇短文能帮助您在使用 NestJS 框架进行应用开发时应对许多常见场景。我几乎每天都会用到这种方法!
文章来源:https://dev.to/avantar/custom-validation-with-database-in-nestjs-gao