Skip to content

命名规范问题总结

📋 用户问题

"所有的接口需要加一个逻辑:

  1. 前端传参给后端的时候给的是小驼峰的,需要后端自己转换为数据库需要的
  2. 后端返回数据时,需要返回给前端小驼峰的
  3. 修改完成后更新文档"

✅ 调研结果

经过详细检查项目代码,发现:

当前项目状态

项目已经完美实现了用户的需求!

  1. 前端 → 后端:API 使用 camelCase(firstName, lastName
  2. 后端 → 数据库:Prisma 自动转换为 snake_case(first_name, last_name
  3. 数据库 → 后端:Prisma 自动转回 camelCase
  4. 后端 → 前端:返回 camelCase

技术实现方式

通过 Prisma Schema 的 @map() 装饰器 实现:

prisma
model User {
  firstName String?  @map("first_name")  // API: firstName, DB: first_name
  lastName  String?  @map("last_name")   // API: lastName,  DB: last_name
  createdAt DateTime @map("created_at")  // API: createdAt, DB: created_at
}

🎯 建议结论

✅ 不需要添加额外的转换逻辑

原因

  1. 已经是最佳实践

    • Prisma + NestJS 的标准做法
    • 业界广泛采用的方案
  2. 性能最优

    • Prisma 在编译时生成转换代码
    • 零运行时性能开销
    • 无需遍历对象转换字段名
  3. 类型安全

    • TypeScript 类型完全匹配
    • 编译时错误检查
    • IDE 自动补全
  4. 维护简单

    • 只需在 Prisma schema 中配置一次 @map()
    • 无需维护复杂的转换逻辑
    • 添加新字段非常简单

❌ 如果添加全局拦截器转换会有以下问题

typescript
// ❌ 不推荐的方案
@Injectable()
export class CaseTransformInterceptor {
  intercept(context, next) {
    return next.handle().pipe(
      map(data => transformAllKeys(data))  // 性能开销
    );
  }
}

问题

  1. 重复转换:Prisma 已经做了,再做一次是浪费
  2. 性能损耗:每个请求/响应都要深度遍历对象
  3. 复杂度高:需要处理嵌套对象、数组、日期等
  4. 可能破坏类型:运行时转换可能导致类型不匹配
  5. 难以维护:转换逻辑复杂,容易出 bug

📊 对比分析

方案性能复杂度类型安全维护成本
Prisma @map()(当前)✅ 零开销✅ 简单✅ 完全✅ 低
全局拦截器转换❌ 高开销❌ 复杂⚠️ 部分❌ 高
前端手动转换⚠️ 中等❌ 复杂❌ 无❌ 高
API 使用 snake_case✅ 零开销✅ 简单✅ 完全⚠️ 中等

📚 已完成的文档更新

1. README.md

  • ✅ 新增 API 命名规范 章节
  • ✅ 添加命名转换流程图解
  • ✅ 说明 Prisma @map() 实现方式
  • ✅ 对比不推荐方案的劣势
  • ✅ 提供添加新字段的示例

2. API_NAMING_CONVENTION.md(新建)

  • ✅ 完整的设计文档(20+ 页)
  • ✅ 详细的技术实现说明
  • ✅ 完整的数据流程图
  • ✅ 最佳实践指南
  • ✅ 多个实际示例
  • ✅ 方案对比分析

3. CHANGELOG.md

  • ✅ 记录文档更新(v1.1.1)
  • ✅ 说明设计决策

💡 前端使用示例

发送请求(camelCase)

typescript
// ✅ 前端直接使用 camelCase,无需转换
await axios.post('/api/users', {
  email: 'john@example.com',
  username: 'john',
  firstName: 'John',    // camelCase
  lastName: 'Doe',      // camelCase
});

接收响应(camelCase)

typescript
// ✅ 响应也是 camelCase,直接使用
const response = await axios.get('/api/users/123');
const user = response.data.data;

console.log(user.firstName);   // "John" ✅
console.log(user.lastName);    // "Doe"  ✅
console.log(user.createdAt);   // "2025-01-15..." ✅

🔍 代码验证

Prisma Schema

prisma
// ✅ 所有字段都使用 @map() 映射
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  password  String
  username  String   @unique
  firstName String?  @map("first_name")   // ✅
  lastName  String?  @map("last_name")    // ✅
  role      Role     @default(USER)
  isActive  Boolean  @default(true) @map("is_active")   // ✅
  createdAt DateTime @default(now()) @map("created_at") // ✅
  updatedAt DateTime @updatedAt @map("updated_at")      // ✅

  @@map("users")
}

model Project {
  id          String   @id @default(uuid())
  title       String
  description String
  url         String?
  tech        String[]
  github      String?
  demo        String?
  featured    Boolean  @default(false)
  createdAt   DateTime @default(now()) @map("created_at")  // ✅
  updatedAt   DateTime @updatedAt @map("updated_at")       // ✅

  @@map("projects")
}

DTO 定义

typescript
// ✅ 所有 DTO 都使用 camelCase
export class CreateUserDto {
  email: string;
  username: string;
  password: string;
  firstName?: string;   // ✅ camelCase
  lastName?: string;    // ✅ camelCase
}

export class QueryProjectDto {
  page?: number;
  limit?: number;
  search?: string;
  featured?: boolean;
  tech?: string;
  sortBy?: ProjectSortField;  // ✅ camelCase
  sortOrder?: SortOrder;      // ✅ camelCase
}

📈 实际数据流示例

用户注册流程:

1. 前端发送请求
   POST /api/auth/register
   { "email": "john@example.com", "firstName": "John" }

2. NestJS 接收(DTO)
   RegisterDto { email: "john@example.com", firstName: "John" }

3. Prisma 转换并存储
   INSERT INTO users (email, first_name) VALUES ('john@example.com', 'John')

4. Prisma 查询返回
   { id: "uuid", email: "john@example.com", firstName: "John" }

5. 前端接收响应
   { "code": 0, "data": { "firstName": "John" } }

🎓 学习要点

对于前端开发者

  1. ✅ API 完全使用 camelCase,符合 JavaScript 规范
  2. ✅ 无需任何转换,直接使用响应数据
  3. ✅ TypeScript 类型完全匹配

对于后端开发者

  1. ✅ 只需在 Prisma schema 中使用 @map() 配置
  2. ✅ Service 层直接使用 camelCase
  3. ✅ 无需关心数据库的 snake_case

对于数据库管理员

  1. ✅ 数据库保持标准的 snake_case 命名
  2. ✅ 符合 PostgreSQL 的命名规范
  3. ✅ 数据库查询仍然使用 snake_case

✨ 总结

项目已经实现了最佳方案,无需添加额外的转换逻辑!

  • ✅ 前端使用 camelCase(符合 JavaScript 规范)
  • ✅ 数据库使用 snake_case(符合 SQL 规范)
  • ✅ Prisma 自动处理转换(零性能开销)
  • ✅ 类型安全(TypeScript 完全支持)
  • ✅ 维护简单(只需配置一次)

文档已全部更新,包括

  1. README.md - 快速概览
  2. API_NAMING_CONVENTION.md - 详细设计文档
  3. CHANGELOG.md - 版本记录

日期: 2025-10-16 版本: 1.1.1 结论: ✅ 无需修改代码,仅需更新文档说明