Skip to content

Before Hooks and After Hooks

Before Hook and After Hook are the two extension points of Instant API. They let business rules run centrally on the backend, so frontends, Agents, scripts, and third-party systems don't each have to implement their own validation and data-masking logic.

1. Execution Chain

Plain
请求进入
  -> Before Hook
  -> Instant API
  -> After Hook
  -> 返回结果

2. Before Hook

Before Hook runs before the Instant API executes. It's the right place for logic that must stop a non-compliant request from going any further.

Typical scenarios:

ScenarioDescription
Uniqueness checksPhone numbers, order numbers, and external reference numbers must not repeat
Permission checksWhether the current user can run create/update/delete/filter
Tenant isolationAutomatically inject or verify tenant_code
Default completionAuto-fill creator, update time, and source
State-machine validationPrevent reverting from completed directly back to in progress

Example:

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 runs once the Instant API has its result. Use it for processing that should be applied uniformly before the result goes back to the caller.

Typical scenarios:

ScenarioDescription
Data maskingHandle sensitive fields such as phone numbers, ID numbers, and email addresses
Field enrichmentStatus labels, display fields, derived fields
ReshapingRestructure the runtime result into a shape that pages consume more easily
Consistent outputEnsure pages, Agents, and third-party systems see the same result

Example:

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. Boundary Between Endpoints and Hooks

CapabilityWhat belongs there
Before HookValidation, authorization, and default values before a single Instant API runs
After HookMasking, field enrichment, and formatting before a single Instant API returns
EndpointMulti-step business orchestration, transactions, external system calls, callback handling
CommonPure functions and utilities shared by multiple Hooks and Endpoints

Don't force complex business flows into Hooks. Keep Hooks short, stable, and predictable; put complex flows in an Endpoint and let the Endpoint call Instant APIs.

5. Best Practices

  • Don't duplicate large chunks of business code across Hooks — factor them into Common.
  • When a Before Hook fails, return a clear error so frontends and Agents can surface it.
  • Avoid slow external calls in After Hooks — they drag down list queries.
  • Test Hooks on write operations, especially the edge cases of create/update/delete.

基于飞书知识库同步生成,内容以飞书源文档为准