2
0
Просмотр исходного кода

✨ feat(wechat-auth): add data validation using parseWithAwait

- import parseWithAwait utility in wechat auth routes
- add response data validation for wechat login, bind and unbind operations
- ensure returned data strictly matches schema definitions

📝 docs(wechat-auth): add parseWithAwait usage documentation

- add "parseWithAwait 使用规范" section
- document overview, usage scenarios, basic usage and best practices
- provide integration examples for wechat auth routes

🐛 fix(wechat-auth): add 400 error response schema for unbind route

- add 400 status code definition in OpenAPI schema for unbind wechat route
- improve error handling consistency across auth endpoints
yourname 6 месяцев назад
Родитель
Сommit
091f7ffc4f

+ 60 - 2
.roo/commands/wechat-auth-微信服务号网页授权登录开发.md

@@ -258,6 +258,7 @@ import { AppDataSource } from '@/server/data-source';
 import { UserService } from '@/server/modules/users/user.service';
 import { AuthService } from '@/server/modules/auth/auth.service';
 import { TokenResponseSchema } from '../login/password';
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
 
 const WechatLoginSchema = z.object({
   code: z.string().min(1).openapi({
@@ -314,7 +315,11 @@ const app = new OpenAPIHono().openapi(wechatLoginRoute, async (c) => {
   try {
     const { code } = await c.req.json();
     const result = await wechatAuthService.wechatLogin(code);
-    return c.json(result, 200);
+    
+    // 使用 parseWithAwait 确保返回数据符合Schema定义
+    const validatedResult = await parseWithAwait(TokenResponseSchema, result);
+    
+    return c.json(validatedResult, 200);
   } catch (error) {
     return c.json({ 
       code: 401, 
@@ -339,7 +344,60 @@ const app = new OpenAPIHono()
 export default app;
 ```
 
-### 5. 注册微信路由
+### 5. 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
+// 在微信登录路由中使用 parseWithAwait
+const app = new OpenAPIHono().openapi(wechatLoginRoute, async (c) => {
+  try {
+    const { code } = await c.req.json();
+    const result = await wechatAuthService.wechatLogin(code);
+    
+    // 使用 parseWithAwait 确保返回数据符合Schema定义
+    const validatedResult = await parseWithAwait(TokenResponseSchema, result);
+    
+    return c.json(validatedResult, 200);
+  } catch (error) {
+    return c.json({
+      code: 401,
+      message: error instanceof Error ? error.message : '微信登录失败'
+    }, 401);
+  }
+});
+```
+
+#### 优势
+- **类型安全**:确保返回数据完全符合Zod schema定义
+- **异步支持**:支持异步验证和转换操作
+- **错误处理**:提供详细的验证错误信息
+- **性能优化**:避免运行时类型错误
+- **向后兼容**:与现有代码完全兼容
+
+#### 最佳实践
+1. **所有查询路由**:GET请求返回数据前必须使用 `parseWithAwait`
+2. **列表查询**:使用 `z.array(EntitySchema)` 格式验证数组
+3. **单条查询**:直接使用实体Schema验证单个对象
+4. **错误处理**:捕获并适当处理验证错误
+
+### 6. 注册微信路由
 
 在API入口文件中注册微信路由:
 

+ 19 - 2
src/server/api/auth/wechat/wechat-bind.ts

@@ -8,6 +8,7 @@ import { AuthService } from '@/server/modules/auth/auth.service';
 import { UserSchema } from '@/server/modules/users/user.schema';
 import { authMiddleware } from '@/server/middleware/auth.middleware';
 import { AuthContext } from '@/server/types/context';
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
 
 const BindWechatSchema = z.object({
   code: z.string().min(1).openapi({
@@ -74,6 +75,14 @@ const unbindWechatRoute = createRoute({
         }
       }
     },
+    400: {
+      description: '请求参数错误',
+      content: {
+        'application/json': {
+          schema: ErrorSchema
+        }
+      }
+    },
     401: {
       description: '认证失败',
       content: {
@@ -90,7 +99,11 @@ const bindApp = new OpenAPIHono<AuthContext>().openapi(bindWechatRoute, async (c
     const user = c.get('user');
     const { code } = await c.req.json();
     const result = await wechatAuthService.bindWechatToUser(user.id, code);
-    return c.json(result, 200);
+    
+    // 使用 parseWithAwait 确保返回数据符合Schema定义
+    const validatedResult = await parseWithAwait(UserSchema, result);
+    
+    return c.json(validatedResult, 200);
   } catch (error) {
     return c.json({ 
       code: 400, 
@@ -103,7 +116,11 @@ const unbindApp = new OpenAPIHono<AuthContext>().openapi(unbindWechatRoute, asyn
   try {
     const user = c.get('user');
     const result = await wechatAuthService.unbindWechatFromUser(user.id);
-    return c.json(result, 200);
+    
+    // 使用 parseWithAwait 确保返回数据符合Schema定义
+    const validatedResult = await parseWithAwait(UserSchema, result);
+    
+    return c.json(validatedResult, 200);
   } catch (error) {
     return c.json({ 
       code: 400, 

+ 6 - 1
src/server/api/auth/wechat/wechat-login.ts

@@ -6,6 +6,7 @@ import { AppDataSource } from '@/server/data-source';
 import { UserService } from '@/server/modules/users/user.service';
 import { AuthService } from '@/server/modules/auth/auth.service';
 import { UserSchema } from '@/server/modules/users/user.schema'
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
 
 const WechatLoginSchema = z.object({
   code: z.string().min(1).openapi({
@@ -70,7 +71,11 @@ const app = new OpenAPIHono().openapi(wechatLoginRoute, async (c) => {
   try {
     const { code } = await c.req.json();
     const result = await wechatAuthService.wechatLogin(code);
-    return c.json(result, 200);
+    
+    // 使用 parseWithAwait 确保返回数据符合Schema定义
+    const validatedResult = await parseWithAwait(TokenResponseSchema, result);
+    
+    return c.json(validatedResult, 200);
   } catch (error) {
     return c.json({ 
       code: 401,