我想开始使用 NestJs 创建 REST API,但我不确定如何设置可扩展层通信对象。
所以从关于如何的文档开始吧 https://docs.nestjs.com/controllers我想出了一个UsersController
处理 HTTP 请求和响应,UsersService
处理控制器和数据库访问器之间的逻辑UsersRepository
它负责数据库管理。
我用类型ORM包 https://docs.nestjs.com/recipes/sql-typeorm由 NestJs 提供,所以我的数据库模型是
@Entity('User')
export class UserEntity extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ unique: true })
username: string;
@Column()
passwordHash: string;
@Column()
passwordSalt: string;
}
但正如您可能知道的那样,该模型必须映射到其他模型,反之亦然,因为您不想将密码信息发送回客户端。我将尝试用一个简单的示例来描述我的 API 流程:
控制器
首先我有一个控制器端点GET /users/:id
and POST /users
.
@Get(':id')
findById(@Param() findByIdParamsDTO: FindByIdParamsDTO): Promise<UserDTO> {
// find user by id and return it
}
@Post()
create(@Body() createUserBodyDTO: CreateUserBodyDTO): Promise<UserDTO> {
// create a new user and return it
}
我设置了DTOs https://en.wikipedia.org/wiki/Data_transfer_object并想首先验证请求。我用类验证器 https://docs.nestjs.com/techniques/validationNestJs 提供的包并创建了一个名为的文件夹请求DTO。通过 id 查找某些内容或通过 url 参数按 id 删除某些内容是可重用的,因此我可以将其放入共享文件夹中以存放其他资源(如组、文档等)。
export class IdParamsDTO {
@IsUUID()
id: string;
}
POST 请求是用户特定的
export class CreateUserBodyDTO {
@IsString()
@IsNotEmpty()
username: string;
@IsString()
@IsNotEmpty()
password: string;
}
现在,控制器输入在执行业务逻辑之前得到验证。对于回复,我创建了一个名为的文件夹响应DTO但目前它只包含数据库用户,没有密码信息
export interface UserDTO {
id: string;
username: string;
}
Services
该服务需要来自参数和正文的捆绑信息。
public async findById(findByIdBO: FindByIdBO): Promise<UserBO> {
// ...
}
public async create(createBO: CreateBO): Promise<UserBO> {
// ...
}
GET 请求只需要 ID,但也许创建一个更好BO https://en.wikipedia.org/wiki/Business_object因为稍后您可能想从字符串 ID 切换到整数。 “find by id”BO是可重用的,我将其移至共享目录
export interface IdBO {
id: string;
}
为了创建用户,我创建了文件夹请求BO
export interface CreateBO {
username: string;
password: string;
}
现在对于响应BO结果将是
export interface UserBO {
id: string;
username: string;
}
你会注意到这和UserDTO。那么其中之一似乎是多余的?
存储库
最后我设置了DAOs https://en.wikipedia.org/wiki/Data_access_object对于存储库。我可以使用自动生成的用户存储库,并处理我上面提到的数据库模型。但随后我必须在我的服务业务逻辑中处理它。创建用户时,我必须在服务中执行此操作,并且仅调用usermodel.save
来自存储库的函数。
否则我可以创建请求DAO
共享的那一个..
export interface IdDAO {
id: string;
}
还有 POST DAO
export interface CreateDAO {
username: string;
password: string;
}
这样我就可以在我的存储库中创建一个数据库用户并使用以下命令映射数据库响应响应DAO但这始终是没有密码信息的整个数据库用户。似乎又产生了很大的开销。
我想知道我使用 3 个请求和 3 个响应接口的方法是否太多并且可以简化。但我想保留一个灵活的层,因为我认为这些层应该高度独立......另一方面,那里会有大量的模型。
提前致谢!