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

340 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OCDP 命名约定对照表
## 快速参考
| 层级 | 变量/属性 | 类型名 | JSON 字段 |
|-----|----------|-------|----------|
| **Backend Go** | 导出: `PascalCase`<br>不导出: `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)
```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)
```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
```typescript
// 文件: 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 - 内部类型
```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
### 安装依赖
```bash
# 安装 Java (如果尚未安装)
sudo apt-get install openjdk-11-jdk
# 安装 OpenAPI Generator CLI (全局)
npm install -g @openapitools/openapi-generator-cli
```
### 生成命令
```bash
# 方式 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):
```bash
# 修改生成文件的所有权
sudo chown -R $USER:$USER frontend/src/api/generated
# 然后重新生成
make openapi-gen-frontend
```
---
## 最佳实践
### ✅ 推荐做法
1. **使用生成的类型进行 API 通信**
```typescript
import type { ClusterResponse } from "@/api/generated";
const clusters = await apiRequest<ClusterResponse[]>("/v1/clusters");
```
2. **统一使用 apiRequest helper**
```typescript
import { apiRequest } from "@/shared/utils/api-helpers";
// 自动处理认证、错误、token 刷新
```
3. **后端修改 OpenAPI 后,重新生成前端 client**
```bash
make openapi-gen-frontend
```
### ❌ 避免的做法
1. **不要手动修改生成的代码**
```typescript
// ❌ 不要修改 /frontend/src/api/generated/ 下的文件
// 这些文件会在重新生成时被覆盖
```
2. **不要直接使用 fetch**
```typescript
// ❌ 不推荐
const response = await fetch("/api/v1/clusters");
// ✅ 推荐
const clusters = await apiRequest("/v1/clusters");
```
3. **避免混淆命名约定**
```typescript
// ❌ 不要在 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
---
## 相关文档
- [API Client 详细说明](./frontend/API_CLIENT_CONVENTIONS.md)
- [OpenAPI 规范](./backend/docs/openapi.yaml)
- [前端 API Helper](./frontend/src/shared/utils/api-helpers.ts)
---
**更新日期**: 2025-11-10