Skip to main content

CRUD 生成器

在项目的整个生命周期中,当我们构建新功能时,通常需要向我们的应用程序添加新资源。 这些资源通常需要执行多个重复操作,每次定义新资源时都必须重复执行这些操作。

介绍

让我们想象一个真实的场景,我们需要为两个实体(比如用户和产品)公开 CRUD 端点。 按照最佳实践,对于每个实体,我们必须执行多个操作,如下所示:

  1. 生成一个模块(nest g mo),以保持代码有序并建立清晰的边界(分组相关组件)。
  2. 生成一个控制器(nest g co),以定义 CRUD 路由(或 GraphQL 应用程序的查询/变更)。
  3. 生成一个服务(nest g s),以实现和隔离业务逻辑。
  4. 生成一个实体类/接口,以表示资源数据形状。
  5. 生成数据传输对象(或 GraphQL 应用程序的输入),以定义数据在网络上的发送方式。

这是很多步骤!

为了帮助加速这个重复的过程,Nest CLI 提供了一个生成器(原理图), 它会自动生成所有样板代码,帮助我们避免所有这些,并使开发人员体验变得更简单。

note

此原理图支持生成 HTTP 控制器、微服务控制器、GraphQL 解析器(既有代码优先,也有架构优先), 以及 WebSocket 网关。

生成新资源

要创建一个新资源,只需在项目的根目录中运行以下命令:

nest g resource

nest g resource 命令不仅生成所有 NestJS 构建块(模块、服务、控制器类), 还会生成实体类、DTO 类以及测试(.spec)文件。

下面是生成的控制器文件示例(用于 REST API):

@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}

@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}

@Get()
findAll() {
return this.usersService.findAll();
}

@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}

@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(+id, updateUserDto);
}

@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
}

它还自动为所有 CRUD 端点(REST API 的路由、GraphQL 的查询和变更、微服务和 WebSocket 网关的消息订阅) 创建占位符,无需费心。

note

生成的服务类不与任何特定的 ORM(或数据源)绑定。这使生成器足够通用,以满足任何项目的需求。 默认情况下,所有方法都将包含占位符,允许您用特定于项目的数据源填充它。

同样,如果要为 GraphQL 应用程序生成解析器, 只需选择 GraphQL (code first)(或 GraphQL(schema first))作为传输层。

在这种情况下,NestJS 将生成一个解析器类,而不是 REST API 控制器:

$ nest g resource users

> ? What transport layer do you use? GraphQL (code first)
> ? Would you like to generate CRUD entry points? Yes
> CREATE src/users/users.module.ts (224 bytes)
> CREATE src/users/users.resolver.spec.ts (525 bytes)
> CREATE src/users/users.resolver.ts (1109 bytes)
> CREATE src/users/users.service.spec.ts (453 bytes)
> CREATE src/users/users.service.ts (625 bytes)
> CREATE src/users/dto/create-user.input.ts (195 bytes)
> CREATE src/users/dto/update-user.input.ts (281 bytes)
> CREATE src/users/entities/user.entity.ts (187 bytes)
> UPDATE src/app.module.ts (312 bytes)
note

要避免生成测试文件,可以传递 --no-spec 标志,如下所示:nest g resource users --no-spec

我们可以看到,不仅创建了所有样板变更和查询,而且一切都是紧密结合的。 我们正在利用 UsersServiceUser 实体和我们的 DTO。

import { Resolver, Query, Mutation, Args, Int } from '@nestjs/graphql';
import { UsersService } from './users.service';
import { User } from './entities/user.entity';
import { CreateUserInput } from './dto/create-user.input';
import { UpdateUserInput } from './dto/update-user.input';

@Resolver(() => User)
export class UsersResolver {
constructor(private readonly usersService: UsersService) {}

@Mutation(() => User)
createUser(@Args('createUserInput') createUserInput: CreateUserInput) {
return this.usersService.create(createUserInput);
}

@Query(() => [User], { name: 'users' })
findAll() {
return this.usersService.findAll();
}

@Query(() => User, { name: 'user' })
findOne(@Args('id', { type: () => Int }) id: number) {
return this.usersService.findOne(id);
}

@Mutation(() => User)
updateUser(@Args('updateUserInput') updateUserInput: UpdateUserInput) {
return this.usersService.update(updateUserInput.id, updateUserInput);
}

@Mutation(() => User)
removeUser(@Args('id', { type: () => Int }) id: number) {
return this.usersService.remove(id);
}
}