This commit is contained in:
D8D Developer
2025-06-27 01:54:18 +00:00
commit ed88ecc0b4
357 changed files with 95752 additions and 0 deletions

View File

@@ -0,0 +1,272 @@
# Hono OpenAPI规范
## 常见不规范问题
1. **路径参数问题**:
- ❌ 使用冒号定义路径参数: `/:id`
- ✅ 必须使用花括号: `/{id}`
2. **参数Schema缺失**:
- ❌ 未定义params Schema
- ✅ 必须定义并添加OpenAPI元数据
3. **参数获取方式**:
- ❌ 使用`c.req.param()`
- ✅ 必须使用`c.req.valid('param')`
4. **URL参数类型转换**:
- ❌ 直接使用z.number()验证URL查询参数
- ✅ 必须使用z.coerce.number()自动转换字符串参数
5. **OpenAPI元数据**:
- ❌ 路径参数缺少OpenAPI描述
- ✅ 必须包含example和description
6. **api响应**:
- ❌ 200响应码缺少
- ✅ 200也必须写c.json(result, 200)
7. **认证中间件**:
- ❌ security: [{ Bearer: [] }],
- ✅ middleware: [authMiddleware],
8. **子路由路径**:
- ❌ path: '/users',
- ✅ path: '/',
- ❌ path: '/users/{id}',
- ✅ path: '/{id}',
## 核心规范
### 1. 路由定义
### 2. 查询参数处理
- **URL参数类型**:
- URL查询参数总是以字符串形式传递
- 必须正确处理字符串到其他类型的转换
- **数字参数处理**:
```typescript
// 错误方式 - 直接使用z.number()
z.number().int().positive() // 无法处理字符串参数
// 正确方式 - 使用z.coerce.number()
z.coerce.number().int().positive() // 自动转换字符串参数
```
- **布尔参数处理**:
```typescript
// 错误方式 - 直接使用z.boolean()
z.boolean() // 无法处理字符串参数
// 正确方式 - 使用z.coerce.boolean()
z.coerce.boolean() // 自动转换字符串参数
```
- **路径参数**:
- 必须使用花括号 `{}` 定义 (例: `/{id}`)
- 必须定义 params Schema 并添加 OpenAPI 元数据:
```typescript
const GetParams = z.object({
id: z.string().openapi({
param: { name: 'id', in: 'path' },
example: '1',
description: '资源ID'
})
});
```
- 路由定义中必须包含 params 定义:
```typescript
request: { params: GetParams }
```
- 必须使用 `c.req.valid('param')` 获取路径参数
- **请求定义**:
```typescript
request: {
body: {
content: {
'application/json': { schema: YourZodSchema }
}
}
}
```
- **响应定义**:
```typescript
responses: {
200: {
description: '成功响应描述',
content: { 'application/json': { schema: SuccessSchema } }
},
400: {
description: '客户端错误',
content: { 'application/json': { schema: ErrorSchema } }
},
500: {
description: '服务器错误',
content: { 'application/json': { schema: ErrorSchema } }
}
}
```
列表响应定义示例
```typescript
// 列表响应Schema, 响应时data应统一用实体中定义的schema
import { RackInfoSchema } from '@/server/modules/racks/rack-info.entity';
const RackListResponse = z.object({
data: z.array(RackInfoSchema),
pagination: z.object({
total: z.number().openapi({
example: 100,
description: '总记录数'
}),
current: z.number().openapi({
example: 1,
description: '当前页码'
}),
pageSize: z.number().openapi({
example: 10,
description: '每页数量'
})
})
});
```
- **路由示例**:
```typescript
const routeDef = createRoute({
method: 'post',
path: '/',
middleware: [authMiddleware],
request: {
body: {
content: { 'application/json': { schema: CreateSchema } }
}
},
responses: {
200: { ... },
400: { ... },
500: { ... }
}
});
```
### 2. 错误处理
- 错误响应必须使用统一格式: `{ code: number, message: string }`
- 必须与OpenAPI定义完全一致
- 处理示例:
```typescript
try {
// 业务逻辑
} catch (error) {
return c.json({ code: 500, message: '操作失败' }, 500);
}
```
### 3. dataSource引入
- 示例:
```typescript
import { AppDataSource } from '@/server/data-source';
```
### 4. service初始化
- 示例:
```typescript
import { WorkspaceService } from '@/server/modules/workspaces/workspace.service';
const workspaceService = new WorkspaceService(AppDataSource);
### 5. 用户context获取
- 示例:
```typescript
const user = c.get('user');
```
- 注意: 确保 `c.get('user')` 已经在 `authMiddleware` 中设置
### 6. AuthContext引用
- 示例:
```typescript
import { AuthContext } from '@/server/types/context';
```
### 7. createRoute, OpenAPIHono 引入
- 示例:
```typescript
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
```
### 8. ErrorSchema 引入
- 示例:
```typescript
import { ErrorSchema } from '@/server/utils/errorHandler';
```
## 进阶规范
### 1. 路由聚合
当多个相关路由需要组合时:
1. **文件结构**:
- 拆分为独立文件 (`create.ts`, `list.ts` 等)
- 创建 `index.ts` 聚合所有子路由
```
src/server/api/
├── [resource]/ # 资源路由目录
│ ├── [id]/ # 带ID的子路由
│ │ ├── get.ts # 获取单条
│ │ ├── put.ts # 更新单条
│ │ └── delete.ts # 删除单条
│ ├── get.ts # 列表查询
│ ├── post.ts # 创建资源
│ └── index.ts # 聚合导出
```
2. **实现**:
```typescript
import listRoute from './get';
import createRackRoute from './post';
import getByIdRoute from './[id]/get';
import updateRoute from './[id]/put';
import deleteRoute from './[id]/delete';
import { OpenAPIHono } from '@hono/zod-openapi';
const app = new OpenAPIHono()
.route('/', listRoute)
.route('/', createRackRoute)
.route('/', getByIdRoute)
.route('/', updateRoute)
.route('/', deleteRoute)
export default app;
```
3. **优势**:
- 保持模块化
- 简化维护
- 统一API入口
## 路由文件代码结构规范
+imports: 依赖导入
+serviceInit: 服务初始化
+paramsSchema: 路径参数定义
+responseSchema: 响应定义
+errorSchema: 错误定义
+routeDef: 路由定义
+app: 路由实例
## src/server/api.ts 统一引入
```ts
import authRoute from '@/server/api/auth/index'
const routes = api.route('/api/v1/auth', authRoute)
```
## 完整示例
```typescript
// 路由实例
const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
try {
// 业务逻辑
return c.json(result, 200);
} catch (error) {
return c.json({
code: 500,
message: error instanceOf Error ? error.message : '操作失败'
}, 500);
}
});
export default app;
```