- 重构项目结构:controllers/services -> modules模块化组织 - 新增Drizzle ORM集成和数据库schema定义 - 添加完整的开发规范文档(.cursor/rules/) - 重新组织插件结构为子目录方式 - 新增用户模块和示例代码 - 更新类型定义并移除试验性代码 - 添加API文档和JWT使用示例 关联任务计划文档
5.0 KiB
5.0 KiB
API 开发规范
文件结构
每个API模块必须包含以下文件:
*.schema.ts
- 请求参数和数据结构定义 + TypeScript类型导出*.response.ts
- 响应格式定义 + 响应类型导出*.service.ts
- 业务逻辑实现(使用类型注解)*.controller.ts
- 路由和控制器(使用Schema验证)*.test.ts
- 测试用例(类型安全的测试数据)
开发流程
- Schema 定义 - 使用 TypeBox 定义请求参数和数据结构,导出TypeScript类型
- Response 定义 - 基于全局响应格式定义各种场景的响应,导出响应类型
- Service 实现 - 编写业务逻辑,使用类型注解确保类型安全
- Controller 实现 - 集成JWT认证、Schema验证、错误处理
- 测试编写 - 使用类型安全的测试数据,覆盖正常、异常、边界场景
必须遵循
1. 认证与授权
// 需要认证的接口必须使用 jwtAuthPlugin
export const controller = new Elysia().use(jwtAuthPlugin).get('/protected-route', handler, options);
2. 参数验证与类型使用
// example.schema.ts - 定义Schema和导出类型
import { t, type Static } from 'elysia';
export const GetUserByUsernameSchema = t.Object({
username: t.String({ minLength: 2, maxLength: 50 }),
});
// 导出TypeScript类型
export type GetUserByUsernameParams = Static<typeof GetUserByUsernameSchema>;
// example.service.ts - Service中使用类型
import type { GetUserByUsernameParams } from './example.schema';
export class ExampleService {
async getUserByUsername(params: GetUserByUsernameParams): Promise<UserInfo> {
const { username } = params; // 类型安全
// 业务逻辑...
}
}
// example.controller.ts - Controller中使用Schema验证
export const controller = new Elysia().use(jwtAuthPlugin).get('/user/:username', handler, {
params: GetUserByUsernameSchema, // 运行时验证
});
要求:
- ✅ 每个Schema必须导出对应的TypeScript类型
- ✅ Service方法必须使用类型注解
- ❌ 禁止行内定义任何参数Schema
3. 统一响应格式
// 成功响应
return {
code: ERROR_CODES.SUCCESS,
message: '操作成功',
data: result,
};
// 错误响应
return {
code: ERROR_CODES.BUSINESS_ERROR,
message: '具体错误信息',
data: null,
};
- 响应内容的类型需要在.response.ts中定义
4. 错误处理
try {
const result = await service.method();
return successResponse(result);
} catch (error) {
Logger.error(new Error(`操作失败: ${error}`));
const errorMessage = error instanceof Error ? error.message : '未知错误';
if (errorMessage.includes('特定错误')) {
set.status = 400;
return errorResponse(ERROR_CODES.BUSINESS_ERROR, '业务错误消息');
}
set.status = 500;
return errorResponse(ERROR_CODES.INTERNAL_ERROR, '服务器内部错误');
}
5. 文档配置
{
detail: {
summary: '接口简要描述',
description: '接口详细描述',
tags: [tags.moduleName],
security: [{ bearerAuth: [] }], // 需要认证时添加
},
response: PredefinedResponses,
}
6. 日志记录
// 接口调用日志
Logger.info(`接口被调用,参数: ${param}, 用户: ${JSON.stringify(user)}`);
// 成功日志
Logger.info(`操作成功,结果: ${result.id}`);
// 错误日志
Logger.error(new Error(`操作失败,错误: ${error}`));
7. 必要的注释
- 接口名称注释
export const controller = new Elysia()
.use(jwtAuthPlugin)
/**
* 根据用户名查询用户信息
* @route GET /api/sample/user/:username
* @description 通过用户名查询用户的详细信息,需要JWT认证
* @param username 用户名,路径参数,长度2-50字符
* @returns 用户信息对象或错误响应
* @modification hotok 2025-06-29 初始实现
*/
.get('/protected-route', handler, options);
禁止事项
- ❌ 直接在 Controller 中写业务逻辑
- ❌ 不进行参数验证
- ❌ 返回非标准格式的响应
- ❌ 暴露敏感信息(如密码哈希)
- ❌ 缺少错误处理和日志记录
- ❌ 不编写测试用例
命名规范
- 文件名:
module.type.ts
(如:user.controller.ts
) - Schema:
GetUserByIdSchema
、CreateUserSchema
- Response:
GetUserSuccessResponse
、UserErrorResponse
- Service 类:
UserService
、导出实例:userService
- Controller:
userController
测试要求
每个接口必须包含:
- ✅ 正常流程测试
- ✅ 参数验证边界测试(最短、最长、无效格式)
- ✅ 业务逻辑异常测试(不存在、权限不足等)
- ✅ 认证相关测试(无Token、无效Token、过期Token)
- ✅ 响应格式验证(状态码、code、message、data结构)