Schema-DSL 项目最佳实践示例
当你准备把 schema-dsl 放进真实应用,而不只是写一个示例文件时,先看本页。本页说明 schema 文件放在哪里、路由如何复用它们,以及如何避免每个请求都重新创建 schema。
推荐的项目结构
完整示例代码
1. 定义 Schema(schemas/user.js)
2. 定义 Schema(schemas/order.js)
3. 统一导出(schemas/index.js)
4. 在路由中使用(routes/user.js)
5. 主应用入口(app.js)
性能对比
❌ 不推荐:每次请求都转换
性能问题:
- ❌ 每次请求都执行 DSL → JSON Schema 转换
- ❌ 1000 次请求 = 1000 次转换
- ❌ 高并发时性能损失明显
- ❌ 如果请求会改变 schema 结构,缓存难以命中,内存和 CPU 压力都会上升
✅ 推荐:项目启动时转换
性能优势:
- ✅ 启动时转换 1 次
- ✅ 1000 次请求 = 0 次转换
- ✅ 高并发时性能最优
缓存与内存边界
稳定的请求级 DSL 通常是性能问题,而不是内存泄漏问题。只要 schema 结构相同,即使处理函数里创建了新的对象,validator 也可以复用编译缓存;但它仍然慢于启动时转换,因为 DSL 对象还需要重新归一化。
长运行服务真正有内存风险的场景,是接收或构造无限多种不同的 schema 结构:
缓存对重复结构有效,但不能替代对动态 schema 基数的约束。
普通请求处理函数里也应避免 new Validator()。如果实例没有被保存,它通常不是保留型内存泄漏;但每次请求都会丢弃 AJV 实例和编译缓存。
使用场景总结
常见错误
❌ 错误1:在路由文件中定义 schema
问题:每次请求都创建新的 schema 对象,浪费性能。
❌ 错误2:在函数内部定义 schema
问题:每次调用函数都创建新的 schema,应该提到函数外部。
✅ 正确:在模块顶部定义
TypeScript 支持
总结
✅ 最佳实践:
- 在单独的
schemas/目录定义所有 schema - 项目启动时加载,转换一次
- 路由中直接使用,不再转换
- 适合生产环境和高并发场景
✅ 性能优势:
- 避免每次请求都重复转换
- schema 复用,内存占用更小
- 响应时间更稳定
✅ 代码优势:
- 集中管理所有验证规则
- 易于维护和修改
- 类型安全(TypeScript)
对应示例文件
示例入口: best-practices-project-structure.ts
说明: 用一个最小的 userSchemas 对象模拟集中定义 / 路由复用结构,直接验证注册与登录两条路径。