Sfoglia il codice sorgente

docs(standards): 修正数组响应处理规范,使用Schema定义而非循环验证

- 添加数组响应Schema定义示例(ChannelListResponseSchema)
- 强调应使用 z.array(ItemSchema) 定义列表响应Schema
- 标记 Promise.all 循环验证为不推荐做法
- 更新关键要点,添加"定义列表响应Schema"要求
- 在5.1节Schema示例中添加列表响应Schema定义

🤖 Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 3 settimane fa
parent
commit
9994222d42
1 ha cambiato i file con 66 aggiunte e 2 eliminazioni
  1. 66 2
      docs/architecture/backend-module-package-standards.md

+ 66 - 2
docs/architecture/backend-module-package-standards.md

@@ -375,8 +375,59 @@ channelCustomRoutes.openapi(createChannelRoute, async (c) => {
 
 #### 数组响应处理
 
+**推荐做法**: 定义数组响应 Schema
+
 ```typescript
-// 处理数组数据 - 使用 Promise.all 批量验证
+// Schema定义
+export const ChannelListResponseSchema = z.object({
+  data: z.array(ChannelSchema).openapi({
+    description: '渠道列表'
+  }),
+  total: z.number().int().min(0).openapi({
+    description: '总数',
+    example: 10
+  })
+});
+
+// 路由定义
+const listChannelRoute = createRoute({
+  method: 'get',
+  path: '/list',
+  responses: {
+    200: {
+      description: '获取列表成功',
+      content: {
+        'application/json': { schema: ChannelListResponseSchema }
+      }
+    },
+    400: {
+      description: '参数错误',
+      content: { 'application/json': { schema: ZodErrorSchema } }
+    }
+  }
+});
+
+// 路由实现
+channelCustomRoutes.openapi(listChannelRoute, async (c) => {
+  try {
+    const result = await channelService.getList(query);
+
+    // ✅ 推荐:直接使用 parseWithAwait 验证整个响应对象
+    const validatedResult = await parseWithAwait(ChannelListResponseSchema, result);
+    return c.json(validatedResult, 200);
+  } catch (error) {
+    if (error instanceof z.ZodError) {
+      return c.json(createZodErrorResponse(error), 400);
+    }
+    return c.json({ code: 500, message: error.message }, 500);
+  }
+});
+```
+
+**❌ 不推荐**: 使用 `Promise.all` 循环验证
+
+```typescript
+// ❌ 不推荐:这种方式效率较低
 const validatedData = await Promise.all(
   result.data.map(item => parseWithAwait(ChannelSchema, item))
 );
@@ -388,13 +439,14 @@ return c.json({ data: validatedData, total: result.total }, 200);
 **响应Schema定义**:
 - **400响应使用 `ZodErrorSchema`**: 因为使用 `createZodErrorResponse` 返回详细的验证错误
 - **其他错误使用 `ErrorSchema`**: 401, 404, 500 等使用简单的错误格式
+- **数组响应定义专用Schema**: 使用 `z.array(ItemSchema)` 定义列表响应Schema
 
 **代码实现**:
 - **必须使用 `createRoute`**: 所有自定义路由必须使用 `createRoute` 定义
 - **必须使用 `parseWithAwait`**: 所有自定义路由返回前必须验证数据
 - **捕获 ZodError**: 在catch块中处理 `z.ZodError` 异常
 - **使用 `createZodErrorResponse`**: 提供统一的Zod错误响应格式
-- **数组使用 `Promise.all`**: 批量验证数组数据
+- **避免使用 Promise.all 循环验证**: 应定义数组响应Schema,直接验证整个响应对象
 
 ### 4.4 关键要点
 
@@ -481,6 +533,17 @@ export const CreateChannelSchema = z.object({
 
 // 更新渠道DTO(所有字段可选)
 export const UpdateChannelSchema = CreateChannelSchema.partial();
+
+// 列表响应Schema
+export const ChannelListResponseSchema = z.object({
+  data: z.array(ChannelSchema).openapi({
+    description: '渠道列表'
+  }),
+  total: z.number().int().min(0).openapi({
+    description: '总数',
+    example: 10
+  })
+});
 ```
 
 ### 5.2 Zod 4.0 coerce使用说明
@@ -520,6 +583,7 @@ export type UpdateChannelDto = z.infer<typeof UpdateChannelSchema>;
 - **使用 `.openapi()` 装饰器**: 添加描述和示例
 - **使用 `z.coerce.date<Date>()` 和 `z.coerce.number<number>()`**: Zod 4.0需要添加泛型参数
 - **使用 `.nullable().optional()`**: 处理可空字段
+- **定义列表响应Schema**: 使用 `z.array(ItemSchema)` 定义数组响应,而不是循环验证
 - **不导出推断类型**: 类型由RPC自动推断,不需要手动导出
 
 ## 6. 软删除规范