Before Hook 与 After Hook 联动方案
Before Hook 和 After Hook 是 Instant API 的两个扩展点。它们让业务规则集中在后端执行,避免前端、Agent、脚本和第三方系统各写一套校验与脱敏逻辑。
1. 执行链路
Plain
请求进入
-> Before Hook
-> Instant API
-> After Hook
-> 返回结果2. Before Hook
Before Hook 在 Instant API 执行前运行,适合处理“不能让不合规请求继续往下走”的逻辑。
典型场景:
| 场景 | 说明 |
|---|---|
| 唯一性校验 | 手机号、订单号、外部单号不能重复 |
| 权限判断 | 当前用户是否能执行 create/update/delete/filter |
| 租户隔离 | 自动注入或校验 tenant_code |
| 默认值补全 | 自动填充创建人、更新时间、来源 |
| 状态机校验 | 禁止从已完成直接回退到处理中 |
示例:
JavaScript
export default async function beforeCreate(params, context) {
const existing = await context.client.models.customers.filter({
where: { phone: { $eq: params.phone } },
currentPage: 1,
pageSize: 1,
});
if (existing.tableData?.length) {
throw new Error("手机号已存在");
}
return {
...params,
tenant_code: context.tenantCode,
created_by: context.userInfo?.id,
};
}3. After Hook
After Hook 在 Instant API 得到结果后运行,适合处理“返回给调用方前需要统一加工”的逻辑。
典型场景:
| 场景 | 说明 |
|---|---|
| 脱敏 | 手机号、身份证、邮箱等敏感字段处理 |
| 补字段 | 状态文案、展示字段、派生字段 |
| 改结构 | 把运行时结果整理成页面更好消费的结构 |
| 统一口径 | 让页面、Agent、第三方系统看到一致结果 |
示例:
JavaScript
export default async function afterFilter(result) {
const rows = result.tableData ?? [];
return {
...result,
tableData: rows.map((row) => ({
...row,
phone: row.phone ? row.phone.replace(/(\\d{3})\\d{4}(\\d{4})/, "$1****$2") : row.phone,
statusText: row.status === "active" ? "已启用" : "未启用",
})),
};
}4. Endpoint 与 Hook 的边界
| 能力 | 应该放什么 |
|---|---|
| Before Hook | 单个 Instant API 执行前的校验、鉴权、补默认值 |
| After Hook | 单个 Instant API 返回前的脱敏、补字段、格式化 |
| Endpoint | 多步骤业务编排、事务、外部系统调用、回调处理 |
| Common | 多个 Hook 和 Endpoint 共享的纯函数或工具函数 |
不要把复杂业务流程硬塞进 Hook。Hook 应保持短、稳定、可预测;复杂流程放到 Endpoint,再由 Endpoint 调用 Instant API。
5. 实践建议
- Hook 里不要写重复的大段业务代码,抽到 Common。
- Before Hook 失败应给出清晰错误,方便前端和 Agent 展示。
- After Hook 不建议做耗时外部调用,避免拖慢列表查询。
- 对写操作 Hook 做测试,特别是 create/update/delete 的边界条件。