返回首页

关于契约生成

分类:现代化开发
发布于:
阅读时间:12 分钟

1. 核心策略:以数据库为底薪,按需“裁剪”

你不需要凭空设计返回结构。既然你有了 Drizzle 定义的数据库表,它就是你的数据原形

  • 默认状态:直接返回数据库的整个 Row(使用 createSelectSchema)。

  • 需要精简时:用 t.Pickt.Omit 删掉敏感字段(如密码、密钥)。

  • 需要关联时:用 t.Object 叠加。


2. 解决“不知道返回什么”:三个典型的契约模板

你可以把常见的返回需求归纳为这三种“模版”,AI 会根据这些模版帮你补全逻辑。

A. 列表页(通用模版)

如果你不知道列表要返回什么,就固定返回“实体列表 + 总数”。

TypeScript

// 以后所有列表接口都复用这个结构
export const CreateListResponse = <T extends TSchema>(itemSchema: T) => 
  t.Object({
    data: t.Array(itemSchema),
    meta: t.Object({
      total: t.Number(),
      page: t.Number(),
      pageSize: t.Number()
    })
  });

// 使用时:
export const UserListResponse = CreateListResponse(UserSelectSchema);

B. 详情页(数据库原形 + 关联)

当你不知道详情页要返回什么,先返回“数据库全字段”,等写到业务发现需要关联数据时,再回来加一个字段。

TypeScript

export const UserDetailResponse = t.Object({
  ...UserSelectSchema.properties,
  // 还不确定关联什么?先留个 Any 或者可选,写业务时再改
  roles: t.Optional(t.Array(t.String())), 
});

C. 操作结果(极简模版)

对于增删改,如果你不知道返回什么,统一返回一个“状态 + ID”。

TypeScript

export const MutationResponse = t.Object({
  success: t.Boolean(),
  id: t.Optional(t.String()),
  message: t.Optional(t.String())
});

3. 工作流:先“抄”数据库,后“改”契约

不要尝试一步到位,你可以尝试这种**“渐进式契约开发”**:

  1. 第一步(粗排):后端直接用 Drizzle 的 SelectSchema 作为返回契约。

  2. 第二步(开发):前端开始写页面,发现页面上需要展示一个“所属部门名称”,但数据库里只有 departmentId

  3. 第三步(修正):回到 packages/contract,在对应的 Response Schema 里加一行 deptName: t.String()

  4. 第四步(对齐):此时后端报错(因为没返回这个字段),前端也报错(因为没处理这个字段)。两边一改,契约达成。


4. 自动化:让脚本帮你“写”初稿

如果你觉得定义每个接口太累,我可以帮你写一个**“契约初稿生成器”**。

这个脚本可以扫描你的 Drizzle Table,自动为每个表生成:

  1. 一个 Create 输入 (Omit ID)

  2. 一个 List 响应 (Array of Table)

  3. 一个 Update 输入 (Partial)

这样你只需要在生成的初稿上删减,而不是从零开始写

5. 总结:如何克服“定义每个接口”的恐惧?

  • 不要怕改:契约不是写死在石头上的,它是可以随业务流转的 TS 代码。

  • 重用大于定义:建立自己的 helper/query-types.t.model.ts,把分页、基础响应包装好。

  • AI 辅助:当你定义了 UserTable,你告诉 AI:“基于这个表,给我写一个 Elysia 的增删改查契约”,它生成的准确率极高。

4. 命名与分界点的终极总结

为了让 AI 彻底不迷路,我建议你在生成的契约里遵循以下分界命名法

  1. Schema 对象 (用于后端校验)

    • XxxContract.Create -> 后端 body 校验。

    • XxxContract.ListQuery -> 后端 query 校验。

  2. Static 类型 (用于前端定义)

    • XxxDTO['Create'] -> 前端表单的 useState 类型。

    • XxxDTO['Response'] -> 前端列表或详情的渲染类型。