对前端转全栈来说,NestJS + TypeScript 是「零语言切换成本、快速落地」的最优解。这一章,我们不聊理论,只做「手把手实操」------ 从环境准备到项目骨架搭建,再到第一个接口开发,全程带代码、带命令,让你 1 小时内跑通全栈项目基础架构。
核心目标:搭建一个「前端可调用、支持 AI API 对接、带数据库连接」的全栈后端骨架,为后续 AI 功能落地打基础。
一、前置环境准备(必做,5 分钟搞定)
NestJS 基于 Node.js,所以先确保你的环境满足要求,按以下步骤操作:
1. 安装 Node.js(核心依赖)
- 要求:Node.js 版本 ≥ 18.x(推荐 18.17.0 或 20.x,LTS 版本更稳定)
- 下载地址:Node.js官网(选对应系统的 LTS 版本)
- 验证:安装完成后,打开终端输入以下命令,能显示版本号即成功:
bash
node -v # 输出 v18.17.0 之类的版本号
npm -v # 输出 9.x 或 10.x 版本号
2. 安装 Nest CLI(项目脚手架,必装)
Nest CLI 能快速创建项目、生成模块 / 控制器 / 服务,前端同学可以理解为「Nest 版的 Vue CLI/Create React App」。
终端执行以下命令全局安装:
bash
npm install -g @nestjs/cli
验证:输入 nest -v,显示版本号即成功(如 10.3.0)。
3. 可选工具(提升开发效率)
- 代码编辑器:推荐 VS Code,安装以下插件:
-
- ESLint(代码校验)
- Prettier(代码格式化)
- NestJS Snippets(Nest 语法提示)
- Prisma(若选 Prisma 数据库,提前安装)
- TypeORM(若选 TypeORM 数据库,提前安装)
- 终端:Windows 推荐 PowerShell/Windows Terminal,Mac/Linux 用自带终端即可。
- API 调试工具:Postman 或 Apifox(后续测试接口用)。
二、创建 NestJS 项目(10 分钟搞定)
1. 初始化项目
终端进入你想存放项目的文件夹(如 ~/projects),执行以下命令创建项目:
arduino
# nest new 项目名(推荐用英文,比如 ai-fullstack-demo)
nest new ai-fullstack-demo
执行后会出现选项:
- 选择包管理器:推荐选 npm(最通用,避免后续依赖问题)
- 等待安装依赖(约 1-3 分钟,取决于网络)
2. 项目目录结构解析(前端视角看懂核心目录)
安装完成后,用 VS Code 打开项目,核心目录结构如下(不用记,先有个印象):
ruby
ai-fullstack-demo/
├── src/ # 核心代码目录(所有业务逻辑写这里)
│ ├── app.controller.ts # 控制器(处理路由、接收请求)→ 类似前端的路由配置
│ ├── app.service.ts # 服务(处理业务逻辑)→ 类似前端的工具函数/API 封装
│ ├── app.module.ts # 根模块(项目入口,整合所有功能模块)→ 类似前端的入口文件
│ └── main.ts # 项目启动文件(配置端口、中间件等)
├── package.json # 依赖配置(和前端一样)
├── tsconfig.json # TypeScript 配置(前端同学熟悉的配置文件)
└── nest-cli.json # Nest CLI 配置(无需修改,默认即可)
对前端同学的通俗解释:
- 控制器(Controller):负责「接收请求」------ 比如前端调用 /api/ai/generate,就由对应的控制器处理路由;
- 服务(Service):负责「处理逻辑」------ 比如调用 OpenAI API、操作数据库,都写在 Service 里;
- 模块(Module):负责「整合功能」------ 比如把 AI 相关的控制器、服务、数据库模型打包成一个 AiModule,结构清晰。
3. 启动项目,验证环境
终端进入项目根目录,执行启动命令:
bash
cd ai-fullstack-demo
npm run start:dev # 开发模式启动(热更新,改代码不用重启服务)
启动成功后,终端会显示:
ini
[Nest] 12345 - 2026/04/07 10:00:00 LOG [NestFactory] Starting Nest application...
[Nest] 12345 - 2026/04/07 10:00:01 LOG [InstanceLoader] AppModule dependencies initialized +100ms
[Nest] 12345 - 2026/04/07 10:00:01 LOG [NestApplication] Nest application successfully started +50ms
打开浏览器访问 http://localhost:3000,能看到 Hello World! 即说明项目启动成功!
三、搭建核心模块(全栈骨架核心,30 分钟搞定)
我们要搭建「用户模块 + AI 模块 + 数据库连接」的基础骨架,后续所有功能(如 AI 生成代码、用户登录)都基于这个结构扩展。
1. 用 Nest CLI 快速生成模块(高效不手写)
Nest CLI 支持自动生成模块、控制器、服务,避免手动创建文件和配置,终端执行以下命令:
bash
# 生成用户模块(处理用户登录、注册等)
nest generate module modules/user
nest generate controller modules/user # 生成用户控制器
nest generate service modules/user # 生成用户服务
# 生成 AI 模块(处理 AI API 调用、生成功能等)
nest generate module modules/ai
nest generate controller modules/ai
nest generate service modules/ai
执行后,项目会新增 src/modules 目录,自动创建 user 和 ai 两个模块,且会自动在根模块 app.module.ts 中导入(不用手动配置,太香了!)。
2. 配置 TypeScript(前端友好,统一类型规范)
打开 tsconfig.json,确保以下配置(默认已配置,重点看这几项):
json
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true, // 启用装饰器(Nest 核心特性)
"target": "ES2021", // 目标 ES 版本,兼容 Node.js 18+
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": true, // 严格 null 检查(避免 undefined 报错,前端熟悉)
"noImplicitAny": true, // 禁止隐式 any 类型(强制写类型,更规范)
"strictBindCallApply": true,
"forceConsistentCasingInFileNames": true
}
}
这些配置和前端项目的 TS 配置基本一致,前端同学不用额外学习。
3. 数据库选型与连接(TypeORM vs Prisma 二选一,前端友好)
全栈项目离不开数据库,NestJS 最常用的两种 ORM 工具是 TypeORM 和 Prisma。两者各有优势,前端同学可根据自身情况选择,以下先对比核心差异,再分别给出实操步骤:
3.1 TypeORM vs Prisma 核心对比(前端视角)
| 对比维度 | TypeORM | Prisma | 前端转全栈适配度 |
|---|---|---|---|
| 核心定位 | 传统 ORM(对象关系映射) | 下一代 ORM(类型安全查询构建器) | 两者均高,Prisma 更易上手 |
| 类型安全 | 依赖 TypeScript 装饰器,需手动定义类型 | 自动生成类型,零手动维护 | Prisma 更优(前端熟悉的 "自动类型" 逻辑) |
| 模型定义 | 用「实体类 + 装饰器」映射数据库表 | 用「Prisma Schema DSL」定义模型 | TypeORM 更贴近前端 "类 + 装饰器" 思维;Prisma 更简洁 |
| 学习成本 | 中(需学装饰器、Repository、查询构建器) | 低(语法简洁,类似写 interface) | Prisma 更低(前端无额外认知负担) |
| 开发效率 | 中等(查询需拼接 Repository 方法) | 高(链式查询 + 自动补全,少写冗余代码) | Prisma 更优 |
| 生态适配 | NestJS 官方推荐,支持所有数据库 | NestJS 无缝集成,支持主流数据库 | 持平 |
| 迁移体验 | 命令行生成迁移文件,需手动调整 SQL | 声明式迁移,自动生成 SQL,支持回滚 | Prisma 更友好(前端不用懂复杂 SQL) |
| 调试体验 | 需打印 SQL 调试,类型错误运行时才暴露 | 编译时类型校验,Prisma Studio 可视化调试 | Prisma 更优 |
选型建议:
- 若你 已用 TypeORM 或熟悉类 + 装饰器语法(比如 React 装饰器),选 TypeORM,无缝衔接前端思维;
- 若你 刚起步、怕麻烦、想少写代码,选 Prisma,自动类型提示 + 可视化工具,开发效率拉满。
3.2 方案一:TypeORM + SQLite(适合已有 TypeORM 经验的同学)
SQLite 是文件型数据库(不用安装服务,零配置,适合开发阶段),TypeORM 是 NestJS 官方推荐 ORM,以下是完整实操:
步骤 1:安装 TypeORM 依赖
bash
npm install @nestjs/typeorm typeorm sqlite3
步骤 2:定义 TypeORM 实体(数据库表结构)
新建 src/modules/user/entities/user.entity.ts:
less
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
import { AiRecord } from '../../ai/entities/ai-record.entity';
@Entity('users') // 映射数据库表 users
export class User {
@PrimaryGeneratedColumn('uuid') // 主键,UUID 类型
id: string;
@Column({ unique: true, length: 64 }) // 唯一字段,字符串类型
username: string;
@Column({ unique: true, length: 128 })
email: string;
@Column({ length: 255 })
password: string;
@CreateDateColumn({ name: 'created_at' }) // 自动维护创建时间
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' }) // 自动维护更新时间
updatedAt: Date;
@OneToMany(() => AiRecord, (aiRecord) => aiRecord.user) // 一对多关联(关联 AI 生成记录)
aiRecords: AiRecord[];
}
新建 src/modules/ai/entities/ai-record.entity.ts:
less
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from '../../user/entities/user.entity';
@Entity('ai_records') // 映射数据库表 ai_records
export class AiRecord {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column('text') // 长文本字段(存储 AI 生成内容)
content: string;
@Column({ length: 32 }) // 生成类型(如 "code"、"text")
type: string;
@Column({ length: 32, default: 'success' }) // 状态(success/error)
status: string;
@Column({ name: 'user_id' }) // 外键字段(关联用户表)
userId: string;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
@ManyToOne(() => User, (user) => user.aiRecords) // 多对一关联
@JoinColumn({ name: 'user_id' }) // 显式指定外键列名,避免歧义
user: User;
}
步骤 3:配置 TypeORM 数据源
新建 src/config/typeorm.config.ts:
javascript
import { DataSource } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { User } from '../modules/user/entities/user.entity';
import { AiRecord } from '../modules/ai/entities/ai-record.entity';
export const getTypeOrmConfig = (configService: ConfigService) => ({
type: 'sqlite', // 数据库类型:SQLite
database: configService.get('DATABASE_URL') || 'dev.db', // 数据库文件(自动生成)
entities: [User, AiRecord], // 注册实体(数据库表映射)
synchronize: false, // 生产环境禁用!用迁移管理表结构
migrations: ['dist/src/migrations/*.js'], // 迁移文件路径
migrationsTableName: 'migrations', // 迁移记录表名
});
在根模块 src/app.module.ts 中导入 TypeORM 配置:
typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './modules/user/user.module';
import { AiModule } from './modules/ai/ai.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { getTypeOrmConfig } from './config/typeorm.config';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }), // 加载环境变量(.env 文件)
TypeOrmModule.forRootAsync({
useFactory: getTypeOrmConfig,
inject: [ConfigService], // 注入配置服务
}),
UserModule,
AiModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
步骤 4:生成数据库表(迁移命令)
arduino
# 1. 生成迁移文件(基于实体类变更)
npx typeorm-ts-node-commonjs migration:generate src/migrations/init-tables --dataSource src/config/typeorm.config.ts
# 2. 执行迁移(创建数据库表)
npx typeorm-ts-node-commonjs migration:run --dataSource src/config/typeorm.config.ts
执行成功后,项目根目录会生成 dev.db 数据库文件,表结构与实体类一致。
3.3 方案二:Prisma + SQLite(适合新手、追求高效的同学)
Prisma 是 TypeScript 友好的 ORM 工具,自动生成类型,不用懂 SQL,以下是完整实操:
步骤 1:安装 Prisma 依赖
css
npm install prisma --save-dev
npm install @prisma/client
步骤 2:初始化 Prisma
csharp
npx prisma init
执行后会生成:
- prisma/schema.prisma:数据库模型配置文件(定义表结构);
- .env:环境变量文件(默认生成 DATABASE_URL,配置数据库连接地址)。
步骤 3:配置数据库连接(SQLite)
打开 .env 文件,修改 DATABASE_URL 为 SQLite 连接地址:
ini
# 原配置(PostgreSQL)注释掉,替换为以下内容
DATABASE_URL="file:./dev.db" # SQLite 数据库文件(会自动生成在 prisma 目录下)
步骤 4:定义 Prisma 模型(数据库表结构)
打开 prisma/schema.prisma,替换为以下代码:
dart
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite" // 数据库类型:SQLite
url = env("DATABASE_URL") // 连接地址(从 .env 读取)
}
// 用户表(存储用户信息,后续登录用)
model User {
id String @id @default(uuid()) // 主键,自动生成 UUID
username String @unique // 用户名(唯一)
email String @unique // 邮箱(唯一)
password String // 密码(后续会加密)
createdAt DateTime @default(now()) // 创建时间
updatedAt DateTime @updatedAt // 更新时间
aiRecords AiRecord[] // 关联 AI 生成记录(一对多)
}
// AI 生成记录表(存储 AI 生成的内容,如代码、文案)
model AiRecord {
id String @id @default(uuid())
content String // 生成的内容(如代码字符串)
type String // 生成类型(如 "code"、"text")
status String @default("success") // 状态(success/error)
userId String // 关联的用户 ID
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id]) // 关联用户表
}
步骤 5:生成数据库和 Prisma 客户端
csharp
npx prisma migrate dev --name init
- --name init:给这次数据库迁移起个名字(初始化);
- 执行成功后,会生成 prisma/dev.db 数据库文件,且自动生成 TypeScript 客户端(用于操作数据库)。
步骤 6:封装 Prisma 全局服务
nest generate service prisma
打开 src/prisma/prisma.service.ts,替换为以下代码:
scala
import { Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
// 模块初始化时连接数据库
async onModuleInit() {
await this.$connect();
}
}
打开 src/prisma/prisma.module.ts,修改为全局模块:
typescript
import { Global, Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Global() // 标记为全局模块,所有模块无需导入即可使用
@Module({
providers: [PrismaService],
exports: [PrismaService], // 导出服务,供其他模块使用
})
export class PrismaModule {}
在根模块 src/app.module.ts 中导入 PrismaModule:
typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './modules/user/user.module';
import { AiModule } from './modules/ai/ai.module';
import { PrismaModule } from './prisma/prisma.module'; // 导入 Prisma 模块
@Module({
imports: [PrismaModule, UserModule, AiModule], // 加入全局模块
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
四、开发第一个接口(验证骨架可用性,二选一)
根据你选择的数据库方案,以下分别给出 TypeORM 和 Prisma 版本的 AI 生成接口,验证模块、数据库、路由是否正常工作:
方案一:TypeORM 版本接口
步骤 1:定义请求参数 DTO
新建 src/modules/ai/dto/generate-text.dto.ts:
typescript
// 定义 AI 生成请求的参数类型(前端可复用)
export class GenerateTextDto {
prompt: string; // 提示词(如 "写一段前端学习文案")
type: string; // 生成类型(如 "text")
userId: string; // 关联的用户 ID(测试用,后续替换为登录用户)
}
步骤 2:编写 AI 服务逻辑
打开 src/modules/ai/ai.service.ts,替换为以下代码:
typescript
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { AiRecord } from './entities/ai-record.entity';
import { GenerateTextDto } from './dto/generate-text.dto';
@Injectable()
export class AiService {
// 注入 AiRecord 实体的 Repository(操作数据库)
constructor(@InjectRepository(AiRecord) private aiRecordRepo: Repository<AiRecord>) {}
// 模拟 AI 生成文本(后续替换为真实 LLM API 调用)
async generateText(dto: GenerateTextDto) {
// 1. 模拟 AI 生成结果(实际项目中替换为 OpenAI/通义千问 API 调用)
const generatedContent = `AI 生成结果(基于提示词:${dto.prompt}):前端转全栈,用 NestJS + TypeORM 真的太香了!`;
// 2. 把生成结果存入数据库
const aiRecord = this.aiRecordRepo.create({
content: generatedContent,
type: dto.type,
userId: dto.userId,
});
await this.aiRecordRepo.save(aiRecord);
// 3. 返回结果(包含数据库记录 ID)
return {
success: true,
data: {
recordId: aiRecord.id,
content: generatedContent,
},
};
}
}
步骤 3:定义接口路由
打开 src/modules/ai/ai.controller.ts,替换为以下代码:
typescript
import { Controller, Post, Body } from '@nestjs/common';
import { AiService } from './ai.service';
import { GenerateTextDto } from './dto/generate-text.dto';
@Controller('api/ai') // 路由前缀:所有接口都以 /api/ai 开头
export class AiController {
constructor(private readonly aiService: AiService) {}
// 定义 POST 接口:/api/ai/generate-text
@Post('generate-text')
async generateText(@Body() dto: GenerateTextDto) {
return this.aiService.generateText(dto);
}
}
方案二:Prisma 版本接口
步骤 1:定义请求参数 DTO
新建 src/modules/ai/dto/generate-text.dto.ts:
typescript
// 定义 AI 生成请求的参数类型(前端可复用)
export class GenerateTextDto {
prompt: string; // 提示词(如 "写一段前端学习文案")
type: string; // 生成类型(如 "text")
userId: string; // 关联的用户 ID(测试用,后续替换为登录用户)
}
步骤 2:编写 AI 服务逻辑
打开 src/modules/ai/ai.service.ts,替换为以下代码:
typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { GenerateTextDto } from './dto/generate-text.dto';
@Injectable()
export class AiService {
constructor(private prisma: PrismaService) {} // 注入 Prisma 全局服务
// 模拟 AI 生成文本(后续替换为真实 LLM API 调用)
async generateText(dto: GenerateTextDto) {
// 1. 模拟 AI 生成结果(实际项目中替换为 OpenAI/通义千问 API 调用)
const generatedContent = `AI 生成结果(基于提示词:${dto.prompt}):前端转全栈,用 NestJS + Prisma 开发效率翻倍!`;
// 2. 把生成结果存入数据库
const aiRecord = await this.prisma.aiRecord.create({
data: {
content: generatedContent,
type: dto.type,
userId: dto.userId,
},
});
// 3. 返回结果(包含数据库记录 ID)
return {
success: true,
data: {
recordId: aiRecord.id,
content: generatedContent,
},
};
}
}
步骤 3:定义接口路由
打开 src/modules/ai/ai.controller.ts,替换为以下代码:
typescript
import { Controller, Post, Body } from '@nestjs/common';
import { AiService } from './ai.service';
import { GenerateTextDto } from './dto/generate-text.dto';
@Controller('api/ai') // 路由前缀:所有接口都以 /api/ai 开头
export class AiController {
constructor(private readonly aiService: AiService) {}
// 定义 POST 接口:/api/ai/generate-text
@Post('generate-text')
async generateText(@Body() dto: GenerateTextDto) {
return this.aiService.generateText(dto);
}
}
步骤 4:测试接口(用 Postman/Apifox)
- 确保项目处于运行状态(npm run start:dev);
- 打开 Postman,创建一个 POST 请求,地址:http://localhost:3000/api/ai/generate-text;
- 请求体(Body)选择 raw → JSON,输入以下参数:
json
{
"prompt": "写一段前端学习文案",
"type": "text",
"userId": "test-user-123" // 测试用用户 ID,后续替换为真实用户
}
- 发送请求,成功返回以下结果即说明接口正常工作:
json
{
"success": true,
"data": {
"recordId": "xxx-xxx-xxx-xxx", // 自动生成的记录 ID
"content": "AI 生成结果(基于提示词:写一段前端学习文案):前端转全栈,用 NestJS + XXX 真的太香了!"
}
}
同时,数据库中会新增一条 AI 生成记录,验证数据库连接成功。
五、项目骨架总结与后续扩展
到这里,我们的 NestJS + TypeScript 全栈项目骨架已经搭建完成,包含:
✅ 基础环境配置(Node.js + Nest CLI + TypeScript);
✅ 核心模块结构(用户模块 + AI 模块 + 数据库模块);
✅ 数据库连接(TypeORM/Prisma 二选一,支持类型安全);
✅ 测试接口(AI 生成文本,包含数据库存储);
✅ 前端友好的类型定义(前后端可复用 interface/dto)。
这个骨架的优势:
- 前后端 TypeScript 类型互通 ------ 前端可直接复用后端的 GenerateTextDto 类型,避免字段不一致;
- 模块化清晰 ------ 后续新增功能(如用户登录、AI 生成代码),只需新增对应模块;
- 可扩展性强 ------ 后续替换为真实 LLM API、切换数据库(如 MySQL/PostgreSQL)、添加权限校验,都能基于这个骨架快速扩展。
下一章预告
下一章,我们将介绍AI本地化基础,了解 AI 本地化部署的项目整体思路。