nest
Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的开发框架
- 原生支持
TypeScript的框架 - 可以基于
Express也可以选择fastify
项目创建
安装全局包
npm i -g @nestjs/cli
创建项目
nest new project-name
项目结构
src
├── app.controller.spec.ts // 针对控制器的单元测试
├── app.controller.ts // 单个路由的基本控制器(Controller)
├── app.module.ts // 应用程序的根模块(Module)
├── app.service.ts // 具有单一方法的基本服务(Service)
├── main.ts // 应用程序的入口文件,它使用核心函数 NestFactory 来创建 Nest 应用程序的实例。
入口文件
内容比较简单, 使用Nest.js的工厂函数NestFactory来创建了一个AppModule实例,启动了 HTTP 侦听器,以侦听main.ts 中所定义的端口。
Module
根模块提供了用来启动应用的引导机制,可以包含很多功能模块。 .mudule文件需要使用一个@Module()装饰器的类,装饰器可以理解成一个封装好的函数,其实是一个语法糖。@Module() 装饰器接收四个属性:
- providers:
Nest.js注入器实例化的提供者(服务提供者),处理具体的业务逻辑,各个模块之间可以共享(注入器的概念后面依赖注入部分会讲解); - controllers:处理
http请求,包括路由控制,向客户端返回响应,将具体业务逻辑委托给providers处理; - imports:导入模块的列表,如果需要使用其他模块的服务,需要通过这里导入;
- exports:导出服务的列表,供其他模块导入使用。如果希望当前模块下的服务可以被其他模块共享,需要在这里配置导出;
Controller
使用@Controller装饰器来定义控制器, @Get是请求方法的装饰器,对getHello方法进行修饰, 表示这个方法会被GET请求调用。
Service
使用@Injectable修饰后的 AppService, 在AppModule中注册之后,在app.controller.ts中使用,我们就不需要使用new AppService()去实例化,直接引入过来就可以用
路由装饰器
@Controller
如每一个要成为控制器的类,都需要借助@Controller装饰器的装饰,该装饰器可以传入一个路径参数,作为访问这个控制器的主路径
// 主路径为 app
@Controller("app")
export class AppController {
constructor(private readonly appService: AppService) {}
....
}
// 需访问 localhost:3000/app
HTTP 方法处理装饰器
@Get、@Post、@Put等众多用于HTTP方法处理装饰器,经过它们装饰的方法,可以对相应的HTTP请求进行响应。同时它们可以接受一个字符串或一个字符串数组作为参数,这里的字符串可以是固定的路径,也可以是通配符。
// 主路径为 app
@Controller("system")
export class AppController {
constructor(private readonly appService: AppService) {}
// 1. 固定路径:
// 可以匹配到 get请求,http://localhost:3000/system/list
@Get("list")
getList(): string {...}
// 可以匹配到 post请求,http://localhost:3000/system/list
@Post("list")
createList():string{...}
// 2.通配符路径(?+* 三种通配符 )
// 可以匹配到 get请求, http://localhost:3000/system/user_xxx
@Get("user_*")
getUser(){return "getUser"}
// 3.带参数路径
// 可以匹配到put请求,http://localhost:3000/system/list/xxxx
@Put("list/:id")
updateList(){ return "update"}
}
提示
修改文件实时监听可使用已配置好的指令npm run start:dev
全局路由前缀
除了上面这些装饰器可以设置路由外, 我们还可以设置全局路由前缀, 比如给所以路由都加上/api 前缀。此时需要修改main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule)
app.setGlobalPrefix('api') // 设置全局路由前缀
await app.listen(9080)
}
bootstrap()
// 访问需 localhost:3000/api/xxx
编写代码
nest 命令
# nest g [文件类型] [文件名] [文件目录]
# 创建模块
nset g mo system
# 创建控制器
nest g co system
注意
创建顺序应为先创建Module后,再创建Controller和Service,这样创建出来的文件在Module中会自动注册
配置接口文档
① 安装
npm install @nestjs/swagger swagger-ui-express -S
② 在main.js中设置
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.enableCors()
....
// 设置swagger文档
const config = new DocumentBuilder()
.setTitle('管理后台')
.setDescription('管理后台接口文档')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('docs', app, document);
await app.listen(9080);
}
bootstrap();
设置完毕可以在localhost:3000/docs里查看生成的文档
接口标签
我们可以根据Controller来分类, 只要添加@ApiTags就可以
import { ApiTags } from '@nestjs/swagger';
import { Body, Controller, Delete, Get, Param, Post, Put, Query } from '@nestjs/common';
@ApiTags("文章")
@Controller('post')
export class PostsController {...}
接口说明
进一步优化文档, 给每一个接口添加说明文字, 让使用的人直观的看到每个接口的含义,不要让使用的人去猜。同样在Controller中, 在每一个路由的前面使用@ApiOperation装饰器:
import { ApiTags,ApiOperation } from '@nestjs/swagger';
export class PostsController {
@ApiOperation({ summary: '创建文章' })
@Post()
async create(@Body() post) {....}
@ApiOperation({ summary: '获取文章列表' })
@Get()
async findAll(@Query() query): Promise<PostsRo> {...}
....
}
接口传参
Swagger的优势之一就是,只要注解到位,可以精确展示每个字段的意义,我们想要对每个传入的参数进行说明
在xxx目录下创建xxx.dto.ts文件
export class CreatePostDto {
readonly title: string
readonly author: string
readonly content: string
readonly cover_url: string
readonly type: number
}
import { CreatePostDto } from './dto/create-post.dto';
@ApiOperation({ summary: '创建文章' })
@Post()
async create(@Body() post:CreatePostDto) {...}
数据验证
Nest.js自带了三个开箱即用的管道:ValidationPipe、ParseIntPipe和ParseUUIDPipe, 其中ValidationPipe 配合class-validator就可以完美的实现我们想要的效果(对参数类型进行验证,验证失败抛出异常)。 管道验证操作通常用在 dto 这种传输层的文件中,用作验证操作 ① 安装
npm install class-validator class-transformer -S
② 在xxx.dto.ts中添加验证,完善错误信息
import { IsNotEmpty, IsNumber, IsString } from 'class-validator'
export class CreatePostDto {
@ApiProperty({ description: '文章标题' })
@IsNotEmpty({ message: '文章标题必填' })
readonly title: string
@IsNotEmpty({ message: '缺少作者信息' })
@ApiProperty({ description: '作者' })
readonly author: string
@ApiPropertyOptional({ description: '内容' })
readonly content: string
@ApiPropertyOptional({ description: '文章封面' })
readonly cover_url: string
@IsNumber()
@ApiProperty({ description: '文章类型' })
readonly type: number
}
③ 最后在main.ts中全局注册管道ValidationPipe
app.useGlobalPipes(new ValidationPipe())
