【nest】1 起步
这篇文章基于nest.js 10.0 版本,简单介绍了如何从零开始创建一个nest项目,以及nest常见的概念,
如controller/service/module/interceptor/pipe/guard/middleware等等。
npm i -g @nestjs/cli
nest new project-name
//生成controller
nest g controller name
//生成service
nest g service name
//生成模块
nest g module name
//生成crud
nest g resource name
controller
controller 用来处理http路由,复杂逻辑传递给 service。
import { Controller, Get, Req } from "@nestjs/common";
import { Request } from "express";
@Controller("cat") // prefix
export class CatController {
@Get() // path
// 参数可以拿到express的Request对象
findAll(@Req() request: Request): string {
// 函数名、没意义
return "This action returns all cats"; //标准模式下:基本类型返回值、对象类型自动序列化成 json
}
}
service
service负责业务模块应用逻辑。
在controller的构造函数里可以注入service,注入后即可通过this.catsService调用方法。
@Controller("cats")
export class CatsController {
//注入service
constructor(private catsService: CatsService) {}
}
尝试使用 fastify 和版本控制
import { NestFactory } from "@nestjs/core";
import { VersioningType } from "@nestjs/common";
import { AppModule } from "./app.module";
import {
FastifyAdapter,
NestFastifyApplication,
} from "@nestjs/platform-fastify";
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter()
);
app.enableVersioning({
type: VersioningType.URI,
});
await app.listen(3000);
}
bootstrap();
为某个 api 添加版本控制
通过@Version装饰器为 api 添加版本号
@Version('1')
@Get()
async findAll(@Query() query: ListAllEntities) {
return this.catService.findAll(query);
}
我当时踩了一个坑,添加完版本号后访问
http://localhost:3000/V1/cat是 404,是自己蠢了,路由区分大小写。
为某个 Controller 添加版本控制
@Controller({
path: "cat",
version: "1",
})
export class CatController {
//some code
}
为整个 app 添加版本控制
app.enableVersioning({
type: VersioningType.URI,
defaultVersion: "1",
});
添加全局中间件
为 api 返回结果提供统一格式。
忽略掉乱七八糟的类型标注,其实这个 class 本质上就是一个简单的拦截器。
next.handle.pipe 暂时不理解。
// common/interceptors/transform.interceptor.ts
// 全局中间件
import {
CallHandler,
NestInterceptor,
ExecutionContext,
Injectable,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { map } from "rxjs";
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(map((data) => ({ data, message: "success" })));
}
}
统一返回格式后,再基于拦截器为 app 添加全局异常拦截。
// common/exceptions/base.exception.filter.ts
// 全局异常拦截
// common/exceptions/http.exception.filter.ts
// 处理http异常
基于 vscode 调试
点 vscode 的 debug,创建配置文件。
删除默认的配置项,点击右下角Add Configuration,输入via npm,选择备选项,即可添加如下配置。
via npm是指通过 npm 启动调试。
start:debug 是 package.json 中定义的脚本。
runtimeVersion 是 node 的版本,vscode 会基于 nvm 切换 node 版本。
internalConsoleOptions 是 vscode 的配置,neverOpen 表示不打开内部控制台。
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch via NPM",
"request": "launch",
"runtimeArgs": ["run-script", "start:debug"],
"runtimeExecutable": "npm",
"runtimeVersion": "20.17.0",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"],
"type": "node"
}
]
}
创建好配置文件后,无需再使用命令行启动调试,直接点 vscode 的 debug 按钮即可。
基于chrome调试
有时需要基于线上环境调试线上问题,可以使用chrome调试。
nest 提供了 start:debug 脚本,本质是开启inspect模式。
随后我们可以通过浏览器访问chrome://inspect,发现 remote target 中有一个 nest 的 app,点击inspect,即可调起devtool进行调试。
开始时的一些坑
- 路由区分大小写
- 直接返回字符串导致前端报错 (无法解析 JSON)
- controller 里的函数忘记 return 导致前端收到的响应是空白的
- 在 service 函数里试图在
setTimeout里返回响应模拟延迟