Files
ocdp-go/docs/development/naming-conventions.md
mangomqy c5e51ed069 ocdp v1
2025-11-13 02:54:06 +00:00

12 KiB
Raw Permalink Blame History

OCDP 命名约定对照表

快速参考

层级 变量/属性 类型名 JSON 字段
Backend Go 导出: PascalCase
不导出: camelCase
PascalCase snake_case
OpenAPI Schema snake_case PascalCase snake_case
Frontend Generated snake_case (引号) PascalCase snake_case
Frontend Internal camelCase PascalCase snake_case

详细说明

1. Backend (Go)

// 文件: backend/internal/adapter/input/http/dto/cluster_dto.go

type ClusterResponse struct {
    ID        string `json:"id"`            // 导出字段: PascalCase, JSON: snake_case
    Name      string `json:"name"`
    HasCAData bool   `json:"has_ca_data"`   // Go: PascalCase → JSON: snake_case
    CreatedAt string `json:"created_at"`
}

// 内部变量
func example() {
    var clusterId string      // 不导出: camelCase
    var clusterName string
}

规则:

  • 导出变量/字段: PascalCase (首字母大写)
  • 不导出变量/字段: camelCase (首字母小写)
  • 类型名: PascalCase
  • JSON 标签: snake_case

2. OpenAPI 规范 (openapi.yaml)

# 文件: backend/docs/openapi.yaml

components:
  schemas:
    ClusterResponse:              # Schema 名称: PascalCase
      type: object
      properties:
        id:                        # 属性: snake_case
          type: string
        name:
          type: string
        has_ca_data:              # 属性: snake_case (与 Go JSON 标签一致)
          type: boolean
        created_at:               # 属性: snake_case
          type: string

规则:

  • 固定字段 (operationId, paths, etc.): camelCase
  • Schema 本身: PascalCase
  • Schema 下面的属性: snake_case

3. Frontend TypeScript - 生成的 API Client

// 文件: frontend/src/api/generated/models/cluster-response.ts
// 自动生成,不要手动修改

export interface ClusterResponse {
    'id'?: string;                // 属性: snake_case (加引号)
    'name'?: string;
    'has_ca_data'?: boolean;      // 保持 snake_case与 JSON 一致
    'created_at'?: string;
}

规则:

  • 类型名: PascalCase
  • 属性: snake_case (带引号)
  • ⚠️ 不要手动修改生成的文件

4. Frontend TypeScript - 内部类型

// 文件: frontend/src/core/types/index.ts
// 前端内部使用的类型定义

export interface Cluster {
  id: string;                    // 内部变量: camelCase
  name: string;
  hasCAData?: boolean;          // camelCase (前端惯例)
  hasCertData?: boolean;
  createdAt: string;            // camelCase
  updatedAt: string;
}

// API 请求类型 (保持与后端一致)
export interface CreateClusterRequest {
  name: string;
  host: string;
  ca_data: string;              // JSON 字段: snake_case
  cert_data: string;            // 与后端 API 保持一致
  key_data: string;
}

规则:

  • 内部变量: camelCase
  • 类型名: PascalCase
  • JSON 序列化 (API 通信): snake_case

数据流转示例

完整的请求-响应流程

┌─────────────────────────────────────────────────────────────┐
│ 1. 前端组件 (camelCase)                                       │
├─────────────────────────────────────────────────────────────┤
│ const cluster = {                                            │
│   name: "Production",                                        │
│   hasCAData: true,        // camelCase                       │
│   createdAt: "2025-11-10"                                    │
│ }                                                            │
└─────────────────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────────────────┐
│ 2. API Request Body (snake_case JSON)                       │
├─────────────────────────────────────────────────────────────┤
│ {                                                            │
│   "name": "Production",                                      │
│   "ca_data": "LS0t...",    // snake_case                     │
│   "cert_data": "LS0t..."                                     │
│ }                                                            │
└─────────────────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────────────────┐
│ 3. Backend Go 结构体 (PascalCase)                             │
├─────────────────────────────────────────────────────────────┤
│ type CreateClusterRequest struct {                           │
│   Name     string `json:"name"`                              │
│   CAData   string `json:"ca_data"`   // Go: PascalCase       │
│   CertData string `json:"cert_data"` // JSON: snake_case     │
│ }                                                            │
└─────────────────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────────────────┐
│ 4. API Response JSON (snake_case)                           │
├─────────────────────────────────────────────────────────────┤
│ {                                                            │
│   "id": "cluster-123",                                       │
│   "name": "Production",                                      │
│   "has_ca_data": true,     // snake_case                     │
│   "created_at": "2025-11-10T08:00:00Z"                       │
│ }                                                            │
└─────────────────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────────────────┐
│ 5. 前端接收 (可以保持 snake_case 或转换为 camelCase)             │
├─────────────────────────────────────────────────────────────┤
│ // 选项 A: 直接使用生成的类型 (snake_case)                      │
│ const cluster: ClusterResponse = response;                   │
│ console.log(cluster.has_ca_data);                            │
│                                                              │
│ // 选项 B: 转换为内部类型 (camelCase)                           │
│ const cluster: Cluster = {                                   │
│   id: response.id,                                           │
│   hasCAData: response.has_ca_data,  // 转换                   │
│   createdAt: response.created_at    // 转换                   │
│ };                                                           │
└─────────────────────────────────────────────────────────────┘

命名转换对照

常见字段名转换

Go (PascalCase) JSON (snake_case) TS Generated TS Internal (camelCase)
ID id 'id' id
Name name 'name' name
ClusterID cluster_id 'cluster_id' clusterId
RegistryID registry_id 'registry_id' registryId
HasCAData has_ca_data 'has_ca_data' hasCAData
CAData ca_data 'ca_data' caData
CertData cert_data 'cert_data' certData
KeyData key_data 'key_data' keyData
CreatedAt created_at 'created_at' createdAt
UpdatedAt updated_at 'updated_at' updatedAt

重新生成 OpenAPI Client

安装依赖

# 安装 Java (如果尚未安装)
sudo apt-get install openjdk-11-jdk

# 安装 OpenAPI Generator CLI (全局)
npm install -g @openapitools/openapi-generator-cli

生成命令

# 方式 1: 使用项目根目录的 Makefile (推荐)
cd /home/mango/workspace/ocdp-go
make openapi-gen-frontend

# 方式 2: 使用前端目录的 npm 脚本
cd /home/mango/workspace/ocdp-go/frontend
npm run openapi-gen

# 方式 3: 直接运行 (如果需要自定义参数)
cd /home/mango/workspace/ocdp-go
openapi-generator-cli generate \
  -i backend/docs/openapi.yaml \
  -g typescript-axios \
  -o frontend/src/api/generated \
  --additional-properties=supportsES6=true,withSeparateModelsAndApi=true,apiPackage=api,modelPackage=models

文件权限问题解决

如果遇到权限问题 (文件属于 root):

# 修改生成文件的所有权
sudo chown -R $USER:$USER frontend/src/api/generated

# 然后重新生成
make openapi-gen-frontend

最佳实践

推荐做法

  1. 使用生成的类型进行 API 通信

    import type { ClusterResponse } from "@/api/generated";
    const clusters = await apiRequest<ClusterResponse[]>("/v1/clusters");
    
  2. 统一使用 apiRequest helper

    import { apiRequest } from "@/shared/utils/api-helpers";
    // 自动处理认证、错误、token 刷新
    
  3. 后端修改 OpenAPI 后,重新生成前端 client

    make openapi-gen-frontend
    

避免的做法

  1. 不要手动修改生成的代码

    // ❌ 不要修改 /frontend/src/api/generated/ 下的文件
    // 这些文件会在重新生成时被覆盖
    
  2. 不要直接使用 fetch

    // ❌ 不推荐
    const response = await fetch("/api/v1/clusters");
    
    // ✅ 推荐
    const clusters = await apiRequest("/v1/clusters");
    
  3. 避免混淆命名约定

    // ❌ 不要在 API 请求中使用 camelCase
    const request = {
      name: "Test",
      caData: "xxx",      // 错误! 应该是 ca_data
    };
    
    // ✅ 正确
    const request = {
      name: "Test",
      ca_data: "xxx",     // 与后端 JSON 标签一致
    };
    

快速检查清单

Backend (Go)

  • 导出字段使用 PascalCase
  • JSON 标签使用 snake_case
  • 更新 OpenAPI 规范与代码保持一致

OpenAPI 规范

  • Schema 名称使用 PascalCase
  • 属性使用 snake_case
  • 与后端 DTO 的 JSON 标签一致

Frontend

  • 从 OpenAPI 重新生成 client
  • 使用生成的类型进行 API 通信
  • 内部类型可以使用 camelCase (可选)
  • 使用 apiRequest helper

相关文档


更新日期: 2025-11-10