第2章 Nest.js入门

学习Nest.js可以通过官方文档:Documentation | NestJS - A progressive Node.js framework。Nest官方文档如图2-1所示。

图2-1 Nest.js官方文档

英文掌握薄弱可采用全文翻译为中文或者在浏览器扩展中下载插件"沉浸式翻译 - 网页翻译插件 | PDF翻译 | 免费",配置后,可通过快捷键进行中英文对照翻译,更适合阅读理解,如图2-2所示。

图2-2 Nest.js官方文档-局部翻译

如果没有学习过Nest.js,第一个疑惑是它是干什么的?Nest.js是提供HTTP服务的框架。并且Nest.js是基于Express实现(即Nest.js底层是默认基于Express封装,也可以选择Fastify),并没有采用原生实现。

Express和Fastify要如何抉择?Express适合做业务层,而Fastify适合做网关层,根据自己实际情况决定。

2.1 安装Nest.js

假如你从未使用过Nest.js,那么第一步是先通过官方文档安装NestJS 命令行工具(CLI),安装后可以在系统的任何目录下使用nest 命令。通过win+R组合快捷键呼出运行窗口,输入cmd进入终端,复制以下命令回车执行。

Vue.js 2的主流时期也是采用CLI的方式构建项目,后续逐渐迁移到Vite中,而NestJS的CLI使用方式和过往的CLI都是一致的。

ts 复制代码
//全局安装 NestJS 命令行工具(CLI)
npm i -g @nestjs/cli

安装结束之后,通过nest --version命令检测NestJS 命令行工具是否安装成功,如图2-3所示。

图2-3 Nest.js命令行工具安装

第二步就可以构建一个Nest.js项目,通过在终端输入以下命令构建项目。

ts 复制代码
// nest new <项目名>
nest new app

会生成如下问题:Which package manager would you ❤️ to use?(您将使用哪个包管理器),有npm、yarn和pnpm可选,推荐pnpm。项目构建成功如图2-4所示。

图2-4 Nest.js构建项目

Nest.js构建的项目结构目录如图2-5所示。

图2-5 Nest.js项目结构目录

从上往下解释分为四部分:

(1)node_modules文件夹:各种项目依赖包,在构建项目时就装好了,无需再次安装。

(2)src文件夹:源代码存放处。

(3)test文件夹:端到端(E2E)测试目录,这个不管。

(4)各类配置文件。

src文件夹下有四个ts文件,作用如下:

ts 复制代码
├── main.ts                    // 应用入口文件
├── app.module.ts              // 根模块(AppModule)
├── app.controller.ts          // 根控制器
├── app.service.ts             // 根服务
└── app.controller.spec.ts     // 控制器单元测试

配置文件总结如表1-1所示。

表1-1 Nest.js项目结构-配置文件

文件名 类型 主要作用 关联工具/框架
package.json 项目配置 定义项目依赖、脚本命令、基本信息 Node.js / npm
package-lock.json 依赖锁 锁定依赖版本,确保一致性 npm
.gitignore 忽略规则 指定哪些文件/目录不应提交到 Git Git
.prettierrc 代码格式化 配置代码格式化规则(Prettier) Prettier
eslint.config.mjs 代码检查 配置 ESLint 代码质量检查规则 ESLint
nest-cli.json CLI 配置 NestJS 命令行工具的配置文件 NestJS CLI
tsconfig.json TS 配置 TypeScript 编译器配置(开发环境) TypeScript
tsconfig.build.json TS 构建配置 TypeScript 生产构建配置 TypeScript / NestJS
jest-e2e.json 测试配置 端到端(E2E)测试的 Jest 配置 Jest
README.md 文档 项目说明文档 -

以上是初始化项目的基础介绍。

2.2 src文件夹内容介绍

src文件夹下的app.controller.spec.ts单元测试文件在开发中是基本不会用到的,因此删除该文件。每次打包构建的时候都会重新创建该单元测试文件,因此我们在nest-cli.json配置文件中添加generateOptions配置项,将spec置为false,做完以上操作,构建项目就不会重新创建app.controller.spec.ts文件了。

ts 复制代码
{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "deleteOutDir": true
  },
  "generateOptions": {
    "spec": false
  }
}

此时src文件夹下4个文件的关联性就很强,文件功能如下4点:

(1)app.controller.ts:控制层,类似前端的路由。

(2)app.module.ts:协调app.controller.ts和app.service.ts文件,我们可以将app.module.ts文件理解为依赖注入的容器,通过@Module()装饰器实现模块整合。

ts 复制代码
//app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

(3)app.service.ts:具体业务实现。

以上3个文件夹分层和MVC架构具备一定的相似性,只不过没有view(视图层)。

(4) main.ts:应用启动入口,创建应用并实现应用的端口监听。

项目启动命令从package.json中的scripts配置项中查看,使用npm run start或者npm run start:dev都可以。启动项目之后到main.ts文件中查看具体端口(默认是3000端口),然后到浏览器中输入http://localhost:3000/进行访问。

Nest.js项目启动后展现的内容是来自app.service.ts文件的具体业务内容,如图2-6所示。

图2-6 Nest.js项目启动-初始化效果

2.3 Nest命令

在终端输入Nest g --help就可以将所有的nest命令弹出,其中有些nest命令可用于创建nest元素,即nest文件,该部分命令总结如表1-2所示。

表1-2 Nest.js命令行部分命令

名称 (Name) 别名 (Alias) 描述 (Description)
application application 生成一个新的应用工作空间
class cl 生成一个新的类
configuration config 生成 CLI 配置文件
controller co 生成控制器声明
decorator d 生成自定义装饰器
filter f 生成过滤器声明
gateway ga 生成网关声明(WebSocket)
guard gu 生成守卫声明
interceptor itc 生成拦截器声明
interface itf 生成接口
library lib 在 monorepo 中生成新的库
middleware mi 生成中间件声明
module mo 生成模块声明
pipe pi 生成管道声明
provider pr 生成提供者声明
resolver r 生成 GraphQL 解析器声明
resource res 生成新的 CRUD 资源
service s 生成服务声明
sub-app app 在 monorepo 中生成新的子应用

如果我们想在src文件夹下创建一个xiaoyu模块,我们需要找到src文件夹,创建xiaoyu文件夹,在xiaoyu文件夹下创建xiaoyu.module.ts文件,并且在app.module.ts中将XiaoyuModule注册到模块中。注意:我们可以在@Module()装饰器的imports配置项中导入其他模块。

ts 复制代码
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { XiaoyuModule } from './xiaoyu/xiaoyu.module';

@Module({
  imports: [XiaoyuModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

但如果通过命令,只需要在终端通过nest g mo xiaoyu就能自动化的完成以上操作,包括自动在app.module.ts文件中注册模块。在终端中体现为新增xiaoyu.module.ts文件,改变app.module.ts文件,如图2-7所示。这可以减少我们一定的心智负担。

图2-7 nest g mo xiaoyu命令效果

除了注册模块,还可以创建service服务层,命令为:nest g s xiaoyu;创建controller控制层,命令为:nest g co xiaoyu。如图2-8所示。xiaoyu.controller.ts和xiaoyu.service.ts文件通过命令生成后,会自动关联到xiaoyu.module.ts文件中,无需开发者额外补充操作。

图2-8 nest g s/co xiaoyu命令效果

我们可以看到这些命令都在一定程度上体现对应的功能,例如刚才三点,因此通过理解关联就很容易记住。

(1)nest g mo <模块名称>=> module(模块)。

(2)nest g s <服务名称>=> service(服务)。

(3)nest g co <控制器名称>=> controller(控制)。

但常用的命令操作主要为:nest g res <模块名称>。表1-2的解释是生成增删改查的资源,听起来并不好理解,实际是生成一份完整结构的增删改查模块--Demo级别。

当我们在终端输入该命令:nest g res user,会弹出一段话What transport layer do you use?(你要使用哪种传输层协议?),然后给出如下5种选择:

(1)REST API。通过传统的 HTTP 路由方式提供接口,是最常用、最直观的 Web 接口风格。

(2)GraphQL(code first)。通过代码定义 GraphQL 架构,让类型和解析逻辑都由代码自动生成。(不好用)

(3)GraphQL(schema first)。先写 .graphql Schema,再根据 Schema 编写解析逻辑,更适合规范化协作。(不好用)

(4)Microservice(non-HTTP)。微服务,通过消息队列、TCP、gRPC 等方式实现服务间通信。

(5)WebSockets。用于创建实时、双向通信的长连接服务,如聊天室或实时推送。

我们选择第一种REST API就可以了。

此时会弹出第二个问题:Would you like to generate CRUD entry points?(你想生成增删改查的模板吗?),选Y(Yes),然后就会开始生成资源。

nest g res user命令效果如图2-9所示。

图2-9 nest g res user命令效果

可以看到该命令一下就创建出controller、module、service三层文件(自动化配置),这些文件内部都会自动初始化一份基础的代码。其文件作用与2.2小节所介绍的src文件夹下的三个同类型文件的作用是一致的。因此展现的内容在user.service.ts文件中,而路由在user.controller.ts文件中。我们打开user.controller.ts文件可以看到默认的get和post方法以及一些参数方法。

如果想要测试Patch,Delete等请求,需要在VSCode中下载rest client,然后在test测试文件夹下创建index.http文件用于发送各种不同的请求来测试API接口。

ts 复制代码
// user.controller.ts
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {} // 来自业务层的展示内容

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

  @Get()
  findAll() {
    return this.userService.findAll(); // 触发默认get请求后,返回业务层中的findAll方法下的展示内容。
  }

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

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

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

因此,只需要在原有URL的后缀添加/user就能访问到user模块下的默认get请求,而get请求的是user.service.ts业务层的内容,/user路由访问效果如图2-10所示。到这里,我们就理解控制层和业务层之间的联系合作(同时在模块层导入注册),并且完成了一次基础的模块创建并展示使用。

图2-10 /user路由的访问效果

除此之外还有dto和entities两个文件夹,两个文件夹作用如下所示:

(1)dto文件夹:数据验证层。主要功能有:定义 API 请求、数据验证(使用 class-validator)、数据转换(使用 class-transformer)等等。内部有create-user.dto.ts和update-user.dto.ts文件,分别用来创建和更新用户的DTO。例如数据验证的做法如下代码所示。

ts 复制代码
// create-user.dto.ts
import {IsNotEmpty,IsString} from 'class-validator'
export class CreateUserDto {
    @IsNotEmpty() // 验证-不能为空
    @IsString() // 验证-需要是一个字符串
    account: string; // 账号
    @IsNotEmpty()
    @IsString()
    password: string; // 密码
}

(2)entities文件夹:实体层。定义数据库的,即映射数据库表结构(ORM 概念),但我们数据库使用Prisma7,所以不在entities文件夹定义,这里用不上了。

所以nest g res <模块名称>做到了nest g mo/s/co <模块名称>的合并效果并且还有额外的数据验证层和实体层,因此nest g res相对于连续写3个命令来创建对应模块结构会更为简便,在日常使用会更加高频。

相关推荐
云起SAAS2 小时前
供求求购供应发布VIP会员抖音快手微信小程序看广告流量主开源
微信小程序·小程序·ai编程·看广告变现轻·供求求购供应发布
没事多睡觉6662 小时前
零基础React + TypeScript 教程
前端·react.js·typescript
liliangcsdn2 小时前
MySQL存储字节类数据的方案示例
java·前端·数据库
_Kayo_2 小时前
React useState setState之后获取到的数据一直是初始值
前端·javascript·react.js
谷哥的小弟2 小时前
HTML5新手练习项目—生命体征监测(附源码)
前端·源码·html5·项目
黎明初时2 小时前
react基础框架搭建3-配置 Redux:react+router+redux+axios+Tailwind+webpack
前端·react.js·webpack
q_30238195562 小时前
宇树机器人又刷第一!具身智能靠强化学习解锁直立行走与快速奔跑
人工智能·python·单片机·机器人·ai编程
Object~2 小时前
2.变量声明
开发语言·前端·javascript
IT_陈寒2 小时前
Vite 3实战:我用这5个优化技巧让HMR构建速度提升了40%
前端·人工智能·后端