“写代码就像谈恋爱——一开始都是 Hello,最后都得连数据库。”
—— 某不愿透露姓名的全栈工程师
🌟 开篇:为什么是 NestJS?
你是不是也经历过这样的场景:
- 用 Express 写了个小项目,结果业务一复杂,代码像意大利面条一样缠在一起?
- 想重构?不敢动!因为不知道改一行会不会崩掉整个服务。
- 团队协作时,有人用
snake_case,有人用camelCase,还有人直接拼音命名……
这时候,你就需要一个有纪律、有结构、有 TypeScript 加持的企业级框架——NestJS!
它不像 Express 那样“自由奔放”,而是像一位穿着西装、打着领带的架构师,温柔又坚定地告诉你:“孩子,代码要这样写。 ”
🧱 什么是 NestJS?一句话说清楚
NestJS = Angular 的架构思想 + Express/Fastify 的底层 + TypeScript 的类型安全 + 依赖注入 + 模块化设计
它不是又一个轮子,而是一套工程化思维的落地实践。尤其适合中大型项目、多人协作、长期维护。
🛠️ 极简上手:5 分钟跑起你的第一个 Nest 项目
# 全局安装 CLI(一次就行)
npm i -g @nestjs/cli
# 创建新项目(比如叫 nest-test-demo)
nest new nest-test-demo
# 进入目录 & 启动
cd nest-test-demo
npm run start:dev
访问 http://localhost:3000,看到 "Hello World!"?恭喜你,已经站在了企业级开发的门口!
💡 小贴士:建议把端口改成
.env文件配置,更优雅:PORT=1234
🧩 核心概念三件套:Module / Controller / Service
NestJS 的灵魂,就是这三个角色:
| 角色 | 职责 | 类比 |
|---|---|---|
| Module | 组织功能单元,声明谁和谁能一起玩 | 包工头:负责协调资源 |
| Controller | 处理 HTTP 请求,路由入口 | 前台接待:接收客户请求 |
| Service | 实现业务逻辑,操作数据 | 后厨大厨:真正干活的人 |
✅ 举个栗子:Todo 列表 API
我们来实现一个简单的 Todo 系统:
GET /todos→ 获取所有任务POST /todos→ 新增任务DELETE /todos/:id→ 删除任务
1. Service:业务逻辑集中地
// todos.service.ts
@Injectable()
export class TodosService {
private todos: Todo[] = [
{ id: 1, title: "周五狂欢", completed: false },
{ id: 2, title: "三角洲首胜", completed: false }
];
findAll() { return this.todos; }
addTodo(title: string) {
const todo = { id: Date.now(), title, completed: false };
this.todos.push(todo);
return todo;
}
deleteTodo(id: number) {
this.todos = this.todos.filter(t => t.id !== id);
return { message: 'Todo deleted', code: 200 };
}
}
🎯 注意:这里用了
@Injectable(),表示这个类可以被“注入”到其他地方使用。
2. Controller:HTTP 接口定义
// todos.controller.ts
@Controller('todos')
export class TodosController {
constructor(private readonly todosService: TodosService) {}
@Get()
getTodos() {
return this.todosService.findAll();
}
@Post()
addTodo(@Body('title') title: string) {
return this.todosService.addTodo(title);
}
@Delete(':id')
deleteTodo(@Param('id', ParseIntPipe) id: number) {
return this.todosService.deleteTodo(id);
}
}
🔍 亮点:
@Body('title'):只取title字段,避免多余参数污染ParseIntPipe:自动把字符串'123'转成数字123,再也不怕类型错误!
3. Module:把它们组装起来
// todos.module.ts
@Module({
controllers: [TodosController],
providers: [TodosService]
})
export class TodosModule {}
然后在 AppModule 中导入:
@Module({
imports: [TodosModule],
controllers: [AppController],
providers: [AppService]
})
export class AppModule {}
搞定!现在你的 API 已经支持完整的 CRUD 了。
🗄️ 连接真实数据库:PostgreSQL 实战
内存里的 Todo 刷新就没了?那不行!我们得连上真正的数据库。
第一步:创建全局 DatabaseModule
// database/database.module.ts
import { Module, Global } from '@nestjs/common';
import { Pool } from 'pg';
import * as dotenv from 'dotenv';
dotenv.config();
@Global() // 全局可用,不用到处 import
@Module({
providers: [
{
provide: 'PG_CONNECTION',
useValue: new Pool({
user: process.env.DB_USER,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: parseInt(process.env.DB_PORT || '5432', 10),
})
}
],
exports: ['PG_CONNECTION']
})
export class DatabaseModule {}
💡 为什么用
provide: 'PG_CONNECTION'?
这是一种自定义 Provider的方式,通过字符串 Token 注入,简单直接(适合小型项目)。进阶可用 Class 或工厂模式。
第二步:在 Controller 中使用数据库
// app.controller.ts
@Controller()
export class AppController {
constructor(
@Inject('PG_CONNECTION') private readonly db: any,
private readonly appService: AppService
) {}
@Get('db-test')
async testConnection() {
try {
const res = await this.db.query('SELECT * FROM users');
return { status: '连接成功', data: res.rows };
} catch (error) {
return { status: '连接失败', error: error.message };
}
}
}
记得在 .env 里配好数据库信息:
DB_USER=postgres
DB_HOST=localhost
DB_NAME=xuebi
DB_PASSWORD=
DB_PORT=5432
⚠️ 安全提醒:生产环境绝不能把密码写在代码里!要用密钥管理或环境变量注入。
🧪 RESTful 设计哲学:语义化你的 API
NestJS 鼓励你写出符合 REST 规范的接口:
| 方法 | 用途 | 示例 |
|---|---|---|
GET | 获取资源 | /users |
POST | 创建资源 | /users |
PUT | 完整更新资源 | /users/1 |
PATCH | 部分更新资源 | /users/1(只改 nickname) |
DELETE | 删除资源 | /users/1 |
🤔 为什么要有 PUT 和 PATCH?
想象你要改微信昵称:
PUT:你得把头像、性别、地区全传一遍(哪怕没变)PATCH:只传{ nickname: "码农老张" }就行!
PATCH 更省流量,更人性化!
🎭 幽默总结:NestJS 的“职场人设”
- Express:自由职业者,穿拖鞋写代码,效率高但容易翻车。
- NestJS:大厂 P7 架构师,西装革履,文档齐全,代码可测可维护。
- 你:刚入职的新人,老板说“用 Nest 写个后台”,你连夜啃完这篇教程,第二天自信提交 PR 👏
🚀 结语:下一步学什么?
这篇文章带你从零搭建了一个带数据库的 NestJS 项目。但 Nest 的世界远不止于此:
- ✅ 使用 TypeORM / Prisma 替代原生 SQL
- ✅ 添加 DTO + ValidationPipe 做参数校验
- ✅ 集成 JWT 鉴权
- ✅ 编写 单元测试 / E2E 测试
- ✅ 部署到 Docker + Nginx
记住:框架只是工具,真正的高手,是在约束中创造自由。