|
|
@@ -105,6 +105,7 @@ export default app;
|
|
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
|
|
import { z } from '@hono/zod-openapi';
|
|
|
import { YourEntitySchema } from '@/server/modules/your-module/your-entity.schema';
|
|
|
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
|
|
|
import { ErrorSchema } from '@/server/utils/errorHandler';
|
|
|
import { AppDataSource } from '@/server/data-source';
|
|
|
import { YourEntityService } from '@/server/modules/your-module/your-entity.service';
|
|
|
@@ -151,7 +152,9 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
|
|
|
return c.json({ code: 404, message: '记录不存在' }, 404);
|
|
|
}
|
|
|
|
|
|
- return c.json(result, 200);
|
|
|
+ // 使用 parseWithAwait 处理响应数据
|
|
|
+ const validatedResult = await parseWithAwait(YourEntitySchema, result);
|
|
|
+ return c.json(validatedResult, 200);
|
|
|
} catch (error) {
|
|
|
return c.json({ code: 500, message: '状态更新失败' }, 500);
|
|
|
}
|
|
|
@@ -167,6 +170,8 @@ import { z } from '@hono/zod-openapi';
|
|
|
import { ErrorSchema } from '@/server/utils/errorHandler';
|
|
|
import { AppDataSource } from '@/server/data-source';
|
|
|
import { YourEntityService } from '@/server/modules/your-module/your-entity.service';
|
|
|
+import { YourEntitySchema } from '@/server/modules/your-module/your-entity.schema';
|
|
|
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
|
|
|
import { AuthContext } from '@/server/types/context';
|
|
|
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
|
|
|
|
|
@@ -217,8 +222,11 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
|
|
|
|
|
|
const [data] = await service.getList(1, 1000, keyword, undefined, filterObj);
|
|
|
|
|
|
+ // 使用 parseWithAwait 处理数据格式
|
|
|
+ const validatedData = await parseWithAwait(z.array(YourEntitySchema), data);
|
|
|
+
|
|
|
if (format === 'csv') {
|
|
|
- const csv = convertToCSV(data);
|
|
|
+ const csv = convertToCSV(validatedData);
|
|
|
return new Response(csv, {
|
|
|
headers: {
|
|
|
'Content-Type': 'text/csv',
|
|
|
@@ -240,7 +248,7 @@ function convertToCSV(data: any[]): string {
|
|
|
|
|
|
const headers = Object.keys(data[0]);
|
|
|
const csvHeaders = headers.join(',');
|
|
|
- const csvRows = data.map(row =>
|
|
|
+ const csvRows = data.map(row =>
|
|
|
headers.map(header => {
|
|
|
const value = row[header];
|
|
|
return typeof value === 'string' && value.includes(',') ? `"${value}"` : value;
|
|
|
@@ -432,6 +440,59 @@ import { BatchDeleteRequestSchema, BatchDeleteResponseSchema } from '@/server/mo
|
|
|
6. **性能考虑**:批量操作要考虑事务处理和性能优化
|
|
|
7. **Schema管理**:所有Schema必须放在指定的schemas目录下
|
|
|
8. **版本兼容**:Schema变更要保持向后兼容性
|
|
|
+9. **数据验证**:所有查询类路由必须使用 `parseWithAwait` 处理响应数据,确保类型安全
|
|
|
+
|
|
|
+## parseWithAwait 使用规范
|
|
|
+
|
|
|
+### 概述
|
|
|
+`parseWithAwait` 是通用CRUD模块提供的数据验证工具,用于确保返回数据的类型安全,支持异步验证和转换。
|
|
|
+
|
|
|
+### 使用场景
|
|
|
+所有涉及数据查询和返回的扩展路由都应使用 `parseWithAwait` 处理响应数据。
|
|
|
+
|
|
|
+### 基本用法
|
|
|
+```typescript
|
|
|
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
|
|
|
+
|
|
|
+// 验证单个实体
|
|
|
+const validatedEntity = await parseWithAwait(YourEntitySchema, entityData);
|
|
|
+
|
|
|
+// 验证实体数组
|
|
|
+const validatedEntities = await parseWithAwait(z.array(YourEntitySchema), entitiesData);
|
|
|
+```
|
|
|
+
|
|
|
+### 集成示例
|
|
|
+```typescript
|
|
|
+// 在扩展路由中使用
|
|
|
+const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
|
|
|
+ try {
|
|
|
+ const data = await yourService.getList();
|
|
|
+
|
|
|
+ // 使用 parseWithAwait 确保数据格式正确
|
|
|
+ const validatedData = await parseWithAwait(z.array(YourEntitySchema), data);
|
|
|
+
|
|
|
+ return c.json({
|
|
|
+ data: validatedData,
|
|
|
+ pagination: { total, current: page, pageSize }
|
|
|
+ }, 200);
|
|
|
+ } catch (error) {
|
|
|
+ return c.json({ code: 500, message: '获取数据失败' }, 500);
|
|
|
+ }
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 优势
|
|
|
+- **类型安全**:确保返回数据完全符合Zod schema定义
|
|
|
+- **异步支持**:支持异步验证和转换操作
|
|
|
+- **错误处理**:提供详细的验证错误信息
|
|
|
+- **性能优化**:避免运行时类型错误
|
|
|
+- **向后兼容**:与现有代码完全兼容
|
|
|
+
|
|
|
+### 最佳实践
|
|
|
+1. **所有查询路由**:GET请求返回数据前必须使用 `parseWithAwait`
|
|
|
+2. **列表查询**:使用 `z.array(EntitySchema)` 格式验证数组
|
|
|
+3. **单条查询**:直接使用实体Schema验证单个对象
|
|
|
+4. **错误处理**:捕获并适当处理验证错误
|
|
|
|
|
|
## 验证步骤
|
|
|
|