NestJS在设计模式上提倡使用Data Transfer Objects(DTOs)和接口(Interfaces)来实现应用程序逻辑的分离以及类型安全。
1. DTOs(Data Transfer Objects)
DTOs在NestJS中通常用于定义数据的传输格式。它们是用来约束客户端发送到服务器端的数据结构,确保数据的一致性和验证。DTOs通常带有装饰器(decorators),这些装饰器可以提供验证规则,确保只有符合这些规则的数据才被接受和处理。
例子:
假设我们有一个创建用户的API,我们可能会定义一个CreateUserDto
类,来确保我们接收到的数据包含username
和password
,并且它们都是字符串:
typescriptimport { IsString } from 'class-validator'; export class CreateUserDto { @IsString() readonly username: string; @IsString() readonly password: string; }
在上面的例子中,class-validator
库提供了@IsString()
装饰器来验证传入数据的类型。
2. 接口(Interfaces)
接口在TypeScript和NestJS中用于定义对象的结构,它们是为了编译时的类型检查而存在。接口定义了对象可以有哪些属性以及这些属性的类型。它们不会编译到JavaScript中,因此不会在运行时提供任何的验证。
例子:
在服务或者模块之间共享数据结构时,我们可以定义一个接口来约定数据的形状。
typescriptinterface User { id: number; username: string; password: string; }
在上述例子中,User
接口描述了用户对象必须包含的属性和类型。任何实现了User
接口的对象都必须有id
,username
和password
这三个属性。
为什么同时需要?
使用DTOs和接口结合起来可以带来以下优势:
- 分层的数据验证:DTOs可以在应用层对传入的数据进行严格的验证,而接口则在编译时提供类型检查,确保代码的正确性。
- 代码可维护性:接口提供了一个清晰的契约定义,可以被服务、控制器和其他类实现,这使得代码更加模块化和可维护。
- 灵活性和扩展性:DTOs可以为特定的操作定义数据格式,例如创建、更新,而接口则定义了应用程序级别的数据模型。这两者的结合使得扩展和重构变得更加容易。
- 隔离变化:如果来自外部的数据需求变化,通常只需要调整DTO,而不需要修改内部使用的接口,这样可以最小化变化对系统的影响。
综上所述,DTOs和接口共同为NestJS提供了一个灵活、可靠和可维护的数据处理框架。通过在编译时和运行时各自发挥作用,它们确保了类型安全和数据一致性,同时也提高了代码的可读性和维护性。