Schema 校验
Schema 校验是 AIRequestGuard 的开发辅助机制。在 dev 模式下,它会对比 adapter 的输出结果与预期的 ViewModel 结构,提前发现字段缺失、类型不匹配等问题。
仅开发环境
Schema 校验逻辑只在 dev: true 时执行,生产构建中不产生任何运行时开销。
传入 Schema
在调用 AIRequestGuard() 时传入 schema 选项,描述期望的 ViewModel 形状(字段名 + 值类型示例):
js
const user = await AIRequestGuard({
id: 'user-detail',
request: () => fetch('/api/user/detail').then(r => r.json()),
schema: {
id: 0, // number
userName: '', // string
mobile: '', // string
deptId: 0, // number
deptName: '', // string
age: 0, // number
avatar: '', // string
createTime: '', // string
},
})ts
const user = await AIRequestGuard({
id: 'user-detail',
request: () => fetch('/api/user/detail').then(r => r.json()),
schema: {
id: 0, // number
userName: '', // string
mobile: '', // string
deptId: 0, // number
deptName: '', // string
age: 0, // number
avatar: '', // string
createTime: '', // string
},
})Schema 的值只用来推断期望类型,不作为默认值。写 0 表示期望 number,写 '' 表示期望 string,写 [] 表示期望 array。
三种差异类型
缺失字段(missingFields)
Schema 中定义了但 adapter 输出中不存在的字段。会触发 Console 警告。
[AIRequestGuard] Schema diff detected for "user-detail":
missingFields: ["email", "phone"]通常原因:adapter 尚未映射该字段,或字段名拼写错误。
类型不匹配(typeMismatches)
字段存在但类型与期望不符。会触发 Console 警告。
[AIRequestGuard] Schema diff detected for "user-detail":
typeMismatches: [{ field: "age", expected: "number", actual: "string" }]通常原因:忘记做类型转换(如 Number(r.age))。
多余字段(extraFields)
Adapter 输出了 schema 中未定义的字段。不触发警告,属于 adapter 主动补充的字段,通常是预期行为(如默认值补齐的 avatar)。
查看完整差异报告
配合 Vite 插件使用时,所有 schema diff 会被汇总到 HTML 报告中。详见真实请求拦截。
Schema 定义技巧
js
// 数组类型:值写空数组
const schema1 = {
total: 0,
items: [], // 期望 array 类型
}
// 对象类型:值写空对象
const schema2 = {
user: {}, // 期望 object 类型
}
// 可以只写关注的字段,不必涵盖所有字段
// adapter 输出中多出的字段会记录为 extraFields 但不报警
const schema3 = {
id: 0,
userName: '',
// 其他字段不写也可以
}ts
// 数组类型:值写空数组
const schema1 = {
total: 0,
items: [], // 期望 array 类型
}
// 对象类型:值写空对象
const schema2 = {
user: {}, // 期望 object 类型
}
// 可以只写关注的字段,不必涵盖所有字段
// adapter 输出中多出的字段会记录为 extraFields 但不报警
const schema3 = {
id: 0,
userName: '',
// 其他字段不写也可以
}在测试中断言 Schema
如果你有单元测试,也可以直接使用 validateSchema 做断言:
js
import { validateSchema, hasDiff } from '@ai-request-guard/core'
const viewModel = myAdapter(rawData)
const diff = validateSchema('user-detail', viewModel, expectedSchema)
expect(hasDiff(diff)).toBe(false)
expect(diff.missingFields).toEqual([])
expect(diff.typeMismatches).toEqual([])ts
import { validateSchema, hasDiff } from '@ai-request-guard/core'
const viewModel = myAdapter(rawData)
const diff = validateSchema('user-detail', viewModel, expectedSchema)
expect(hasDiff(diff)).toBe(false)
expect(diff.missingFields).toEqual([])
expect(diff.typeMismatches).toEqual([])