跳转至

CRUD 生成器

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

介绍

让我们设想一个真实的场景,其中我们需要为两个实体公开 CRUD 端点,比如 User**和**Product 实体。 按照最佳实践,对于每个实体,我们必须执行以下几个操作:

  • 生成一个模块(nest g mo)来保持代码的组织,并建立清晰的边界(分组相关组件)
  • 生成一个控制器(nest g co)来定义 CRUD 路由(或 GraphQL 应用程序的查询/突变)
  • 生成服务(nest g s)来实现和隔离业务逻辑
  • 生成一个实体类/接口来表示资源数据形状
  • 生成数据传输对象(或 GraphQL 应用程序的输入),以定义数据将如何通过网络发送

这是很多步骤!

为了帮助加快这个重复的过程,Nest CLI提供了一个生成器(示意图),可以自动生成所有的样板代码,帮助我们避免做所有这些事情,并让开发人员的体验更简单。

!!! info Note 原理图支持生成**HTTP**控制器、Microservice**控制器、**GraphQL**解析器(代码优先和模式优先)和**WebSocket 网关。

生成新资源

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

$ nest g resource

nest g resource command not only generates all the NestJS building blocks (module, service, controller classes) but also an entity class, DTO classes as well as the testing (.spec) files.

Below you can see the generated controller file (for 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 网关的消息订阅)——所有这些都不需要动一根手指。

Warning

生成的服务类**不**与任何特定的**ORM(或数据源)** 绑定。

这使得生成器足够通用,可以满足任何项目的需要。 默认情况下,所有方法都将包含占位符,允许您使用特定于项目的数据源填充占位符。

同样,如果你想为一个 GraphQL 应用程序生成解析器,只需选择GraphQL(代码优先)(或GraphQL(模式优先))作为你的传输层。

在这种情况下,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)

Hint

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

我们可以在下面看到,不仅创建了所有的样板突变和查询,而且所有的东西都联系在一起。 我们正在使用UsersService, User Entity,我们的 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);
  }
}