创建一个nest应用

创建项目

1nest new interview-server-app

prisma

安装与初始化

Prisma 是一个现代的 ORM(对象关系映射)工具,用于 Node.js 和 TypeScript。它可以帮助你更方便地操作数据库,同时提供类型安全的查询功能。

将 Prisma 与 Nest.js 结合使用,可以让你更轻松地开发数据库驱动的应用程序。

步骤 1:安装 Prisma 相关依赖

在你的 Nest.js 项目中,运行以下命令来安装 Prisma 的相关依赖:

  • prisma:是 Prisma 的 CLI 工具,用于初始化和管理 Prisma。
  • @prisma/client:是 Prisma 的客户端库,用于在代码中与数据库交互。
1pnpm add @prisma/client
2pnpm add -D prisma

步骤 2:初始化 Prisma

运行以下命令初始化 Prisma:

1npx prisma init

该命令会在项目根目录下生成以下文件:

  • .env:用于存储数据库连接信息。
  • prisma/schema.prisma:用于定义数据库模型和配置。

步骤 3:配置数据库连接

修改 .env 文件:

DATABASE_URL="postgresql://dancy:rootroot@localhost:5432/interview_question_app?schema=public"

配置 prisma/schema.prisma

generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") }

定义数据模型

根据你的数据库表设计,转换为 Prisma 模型:

generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // 用户表 model User { id Int @id @default(autoincrement()) email String @unique password String name String? avatar String? phone String? @unique role UserRole @default(USER) status Boolean @default(true) lastLoginAt BigInt? createdAt BigInt @default(dbgenerated("EXTRACT(EPOCH FROM NOW())::BIGINT")) updatedAt BigInt @default(dbgenerated("EXTRACT(EPOCH FROM NOW())::BIGINT")) favorites UserFavorite[] marks UserMark[] comments Comment[] }

生成迁移文件与同步数据库

步骤 1:生成迁移文件

运行以下命令,将定义的模型同步到数据库中:

1# 生成迁移文件
2npx prisma migrate dev --name init
3
4# 如果不需要迁移历史,也可以直接同步数据库结构
5npx prisma db push

这会:

  • prisma/migrations 下生成 SQL 迁移文件
  • 自动执行迁移,同步到数据库
  • 生成 Prisma Client 代码

每次修改 schema.prisma 文件后,都需要运行此命令来更新数据库。

步骤 2:查看数据库结构

1npx prisma studio

访问 http://localhost:5555 可直观管理数据。

步骤 3:生成 Prisma Client

1npx prisma generate

Nest 集成 Prisma

步骤 1:创建 Prisma 服务

在 Nest.js 中创建一个 Prisma 服务,用于与数据库交互:

1nest generate service prisma

src/prisma/prisma.service.ts 中初始化 Prisma 客户端:

1// src/prisma/prisma.service.ts
2import { Injectable, OnModuleInit } from '@nestjs/common';
3import { PrismaClient } from '@prisma/client';
4
5@Injectable()
6export class PrismaService extends PrismaClient implements OnModuleInit {
7  async onModuleInit() {
8    await this.$connect();
9  }
10}

步骤 2:全局导入 Prisma 模块

1// src/app.module.ts
2import { PrismaService } from './prisma/prisma.service';
3
4@Module({
5  providers: [PrismaService],
6})

Docker

配置 Dockerfile

1# 构建阶段
2# 使用 node:18-alpine 作为基础镜像,并给这个阶段命名为 builder,用于后续多阶段构建引用
3FROM node:18-alpine AS builder
4
5# 设置工作目录为 /app ,后续的命令都会在这个目录下执行
6WORKDIR /app
7
8# 只复制 package.json 和 package-lock.json(如果存在)
9# 这样做是为了利用 Docker 的缓存机制,如果依赖没有变化,就可以使用缓存
10COPY package*.json ./
11
12# 安装所有依赖(包括开发依赖)
13# 这些依赖在构建阶段是必需的
14RUN npm install
15
16# 复制所有源代码到容器中
17# 这一步放在依赖安装后面,是因为源代码更容易变化,这样可以最大化利用缓存
18COPY . .
19
20# 生成 Prisma Client
21# 必须在构建前生成,因为应用依赖这些生成的代码
22RUN npx prisma generate
23
24# 构建 Nest.js 应用
25# 生成的文件会在 dist 目录下
26RUN npm run build
27
28# 生产阶段
29# 开始新的构建阶段,使用相同的基础镜像,这个阶段的镜像将是最终的生产镜像
30FROM node:18-alpine
31
32# 在新阶段同样设置工作目录
33WORKDIR /app
34
35# 同样复制 package 文件,为生产依赖安装做准备
36COPY package*.json ./
37
38# 只安装生产环境需要的依赖
39# --only=production 确保不安装开发依赖,减小最终镜像大小
40RUN npm install --only=production
41
42# 复制 Prisma schema 并重新生成 client
43# 生产环境也需要 Prisma Client
44COPY prisma ./prisma/
45RUN npx prisma generate
46
47# 从构建阶段复制编译好的代码到生产阶段
48# 只复制需要的 dist 目录,而不是所有源代码
49COPY --from=builder /app/dist ./dist
50
51# 声明容器将使用 3000 端口
52EXPOSE 3000
53
54# 容器启动时执行的命令
55CMD ["npm", "run", "start:prod"]
56
57# 为什么要使用多阶段构建?
58# 1. 减小镜像大小 :最终镜像只包含运行时必需的文件
59# 2. 提高安全性 :不包含源代码和开发工具
60# 3. 优化构建缓存 :合理的层次结构可以最大化利用 Docker 缓存
61# 4. 分离构建环境和运行环境 :构建工具和依赖只存在于构建阶段
62
63# 以下命令构建和运行容器:
64# docker build -t interview-server-app .
65# docker run -p 3000:3000 interview-server-app

配置 docker-compose.yml

1# 指定 Docker Compose 文件格式版本
2version: '3.8'
3
4# 应用服务配置
5services:
6  app:
7    # 定义应用服务的构建配置
8    build:
9      context: .
10      dockerfile: Dockerfile
11    # 端口映射配置
12    ports:
13      - "3000:3000"
14    # 环境变量配置
15    environment:
16      - NODE_ENV=production
17      - DATABASE_URL=postgresql://dancy:rootroot@postgres:5432/interview_question_app?schema=public
18    # 定义服务依赖关系
19    depends_on:
20      - postgres
21    # 容器重启策略
22    restart: unless-stopped
23    # 网络配置
24    networks:
25      - app-network
26
27  postgres:
28    # 指定官方镜像
29    image: postgres:latest
30    # 数据库初始化配置
31    environment:
32      - POSTGRES_USER=dancy
33      - POSTGRES_PASSWORD=rootroot
34      - POSTGRES_DB=interview_question_app
35    # 端口映射配置
36    ports:
37      - "5432:5432"
38    # 数据持久化配置
39    volumes:
40      - postgres_data:/var/lib/postgresql/data
41    # 容器重启策略
42    restart: unless-stopped
43    # 网络配置
44    networks:
45      - app-network
46
47# 卷
48volumes:
49  postgres_data:
50
51# 网络
52networks:
53  app-network:
54    driver: bridge

.dockerignore

node_modules npm-debug.log dist .git .env .env.* *.md .gitignore .dockerignore .vscode coverage test

命令

1{
2  "scripts": {
3    "docker:up": "docker-compose up -d",
4    "docker:down": "docker-compose down",
5    "docker:build": "docker-compose build",
6    "docker:rebuild": "docker-compose up -d --build"
7  }
8}

Swagger

步骤 1:安装 Swagger 模块

1pnpm add @nestjs/swagger swagger-ui-express

步骤 2:配置 Swaggersrc/main.ts 中配置 Swagger:

1import { NestFactory } from '@nestjs/core';
2import { AppModule } from './app.module';
3import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
4async function bootstrap() {
5  const app = await NestFactory.create(AppModule);
6  const config = new DocumentBuilder()
7    .setTitle('Interview Question API')
8    .setDescription('API for managing interview questions')
9    .setVersion('1.0')
10    .build();
11  const document = SwaggerModule.createDocument(app, config);
12  SwaggerModule.setup('api', app, document);
13  await app.listen(process.env.PORT ?? 3000);
14}
15bootstrap();

步骤 3:运行以下命令启动项目

1npm run start:dev

步骤 4:访问 Swagger 打开浏览器,访问 http://localhost:3000/api,查看 Swagger 文档并测试 API。