目录
当构建一个强大的可扩展的API时,在你的应用程序中实施适当的验证是很重要的,这不仅是为了安全,也是为了保持你的数据库清洁。如果你正在使用强大的后端API,NestJS可以是一个很好的工具,而且,你可以用NestJS和Joi添加对象验证,使你的应用程序安全。
这篇文章将告诉你如何通过一个基本的CRUD例子在NestJS中实现Joi对象验证。
什么是NestJS?
NestJS深受Angular的启发,是一个 特别流行的框架,用于构建可扩展和强大的应用程序。它提供了一个基于模块、控制器和提供者的简洁架构,以帮助你开始使用。它支持TypeScript,但你也可以用普通的JavaScript编写你的应用程序。
NestJS不会给你强加任何编程范式。你可以自由地使用面向对象、函数式或功能反应式编程。它还在引擎盖下提供了一个优秀的路由机制,并原生支持HTTP服务器框架Express。你也可以配置你的NestJS应用程序来使用Fastify。
NestJS的构建块
NestJS有三个主要的构建块:模块、控制器和提供者。
- 模块:模块用于模块化代码库并将其分割成可重用的组件。被分组的TypeScript文件用
@Module装饰器描述,以提供元数据。NestJS使用这些文件来组织应用程序的结构 - 控制器:控制器控制传入的请求并向客户端发送适当的响应
- 提供者:提供者是NestJS的基本概念。服务、工厂、助手、资源库等,在Nest中被视为提供者。提供者可以作为Nest中的一个依赖关系被注入。
为什么使用NestJS?
近年来,Node.js已成为一种流行的编程语言,而且,由于开发人员希望更快地编写可投入生产的API,对高质量的后端框架的需求也在增加。进入NestJS,它可以帮助开发者更快地编写高效的代码。
让我们来讨论一下使用NestJS的好处。
- TypeScript。NestJS默认使用TypeScript,但你也可以用vanilla JavaScript编写NestJS代码。
- 微服务。NestJS支持GraphQL、WebSockets、gRPC和MQTT,以及REST APIs。对这些工具的支持有助于编写微服务。
- CLI:Nest也有自己的CLI,它使你能够创建、运行、构建你的应用程序,以及更多。
- 高质量的文档。NestJS有很好的文档,可以帮助你深入理解各种概念。它甚至提供由NestJS团队成员创建的官方课程
- 测试。NestJS提供了对使用Jest测试你的应用程序的支持,或者你选择的任何其他测试框架。NestJS甚至提供了一个自己的测试包。
什么是Joi?
所有的开发者都知道,验证来自客户端的数据是至关重要的。如果你曾经在Node.js中使用过MongoDB和mongoose,你可能对mongoose模式很熟悉。Mongoose模式有助于描述数据,并轻松为数据添加验证器。Joi与schemas非常相似。
Joi是一个广泛使用的Node.js数据验证库,提供了一个简单、直观、可读的API来描述数据。它主要用于验证从API端点发送的数据,并允许你创建你想接受的数据类型的蓝图。
下面是一个用Joi描述模式的简单例子。
const schema = Joi.object().keys({
name: Joi.string().alphanum().min(3).max(30).required(),
birthyear: Joi.number().integer().min(1970).max(2013),
});
用NestJS构建一个基本的API
NestJS提供了许多选项,可以根据你的需求来构建代码,例如CRUD配方。这允许你在几秒钟内从Nest CLI中用端点搭建一个CRUD的支架。
要在你的电脑上安装Nest CLI,运行以下命令。
npm i -g @nestjs/cli
下一步是生成一个Nest应用程序。Nest CLI使用以下命令。
nest new project-name
这里,project-name 是项目的名称。命令完成后,运行下面的命令,将CRUD端点支架化。
nest g resource users
它会问你几个问题,比如要使用哪个传输层。一旦你根据你的偏好选择了这些选项,Nest将为CRUD API提供支架。例如,一个带有users 端点的API将由上述命令生成。你可以看到新的users 文件夹。
现在,如果你用npm run start:dev 运行应用程序,你会看到控制台中记录的端点。你的服务器将在端口3000 启动。
你可以通过访问端点或打开users.controllers.ts 文件来检查端点。这个文件包含CRUD API的路由。每个API的服务都在users.service.ts 文件中定义,所有这些文件都在users 文件夹下。
对象验证的重要性
users.controllers.ts 如果你看一下GET 文件中寻找单一项目的方法,你会发现没有设置验证。你可以使用任何东西作为ID,而Nest不会抛出验证错误。
OWASP的十大安全风险列表中提到,注入攻击仍然是最流行的安全风险之一。OWASP还提到,当 "用户提供的数据没有经过应用程序的验证、过滤或消毒 "时,应用程序就容易受到注入攻击。
这清楚地表明,数据验证是一个重要的安全问题,在构建应用程序时要牢记。有一些内置的管道,可以验证或修改输入。NestJS有八个内置管道。如果你想让ID只能是整数类型的,你可以使用ParseIntPipe 管道。这里有一个例子。
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: string) {
return this.usersService.findOne(+id);
}
如果你试图用数字以外的任何ID打到端点,你会收到以下错误。

使用一个内置的管道很简单,但是将其用于一个大型的模式是很复杂的。Joi使得在NestJS中设计模式和实现验证变得更容易。让我们为NestJS项目实现Joi。
在NestJS中实现Joi
一般来说,任何可以注入NestJS的脚本都是Pipe 类。管道主要有两个使用情况。
- 转换输入数据
- 验证输入数据
你可以在官方文档中阅读更多关于管道的内容。
第一步是安装必要的包。这里,只有Joi包是必需的。运行下面的命令来安装该包。
npm i joi
现在,在users 目录内创建一个名为validation.pipe.ts 的新文件。创建一个自定义管道来实现验证是非常直接的。这里有一个代码片段来帮助你理解。
import {
PipeTransform,
BadRequestException,
ArgumentMetadata
} from '@nestjs/common';
export class ValidationPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
return value;
}
}
任何传入这个管道构造函数的模式都将被检查为配置的Joi验证模式。为了使上述验证器工作,打开dto 文件夹内的create-user.dto.ts 文件。
在这里,定义一个API在保存数据时将使用的模式类型。为了简单起见,假设用户发送的模式和数据库持有的模式具有相同的结构。
我们假设API将firstname,lastname,email,isVerified, 和phoneNumber 作为输入。DTO将看起来像这样。
export class CreateUserDto {
public firstname: string;
public lastname: string;
public isVerified: boolean;
public email: string;
public phoneNumber: number;
}
现在,在user.dto.js 文件内定义Joi模式。你也可以使用单独的文件来存储模式。在这个例子中,Joi的用户模式很简单。
import Joi from 'joi';
export const UserSchema = Joi.object({
firstname: Joi.string().required(),
lastname: Joi.string().required(),
email: Joi.string().email().required(),
isVerified: Joi.boolean().required(),
phoneNumber: Joi.number(),
}).options({
abortEarly: false,
});
该模式是非常不言自明的。string() 方法确保输入的类型是string ,而required() 方法确保字段在输入里面。同样地,boolean 和number 确保类型是布尔型或数字型。
options 方法在一个对象内接受其他选项。abortEarly 方法,当设置为true 时,当它发现第一个错误时停止验证。否则,它会返回所有的错误。
现在模式已经准备好了,是时候相应地更新验证管道了。
这里是完整的validation.pipe.ts 文件。
import { PipeTransform, BadRequestException } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UserSchema } from './dto/user.dto';
export class CreateUserValidatorPipe implements PipeTransform<CreateUserDto> {
public transform(value: CreateUserDto): CreateUserDto {
const result = UserSchema.validate(value);
if (result.error) {
const errorMessages = result.error.details.map((d) => d.message).join();
throw new BadRequestException(errorMessages);
}
return value;
}
}
自定义验证器类接受并返回CreateUserDto 类。const result = UserSchema.validate(value); ,根据定义的Joi模式验证结果。如果结果有任何错误,则使用map 方法对结果进行映射。错误信息被连接在一起。最后,错误信息被发送到客户端。否则,它返回输入值。
如果输入值通过了验证,它将根据user.service.ts 文件内定义的方法显示信息,"This action adds a new user ,"。
我们现在已经在NestJS中实施了Joi。你可以通过向端点发送JSON有效载荷来查看验证是否有效 [http://localhost:3000/users](http://localhost:3000/users).

上面的图片显示了有效载荷通过验证时的样子。同样地,下面的图片显示了基于验证的不同错误。

总结
本文概述了NestJS和Joi以及验证在我们应用程序中的重要性,然后引导你在NestJS应用程序中实现验证。我希望你觉得它很有用。