---
url: /docs/recipes/new-procedure.md
---
# 新增接口

## 创建与注册

先明确接口是公开查询还是私有操作，输入、返回字段和身份范围。下面创建一个当前用户摘要，不涉及新增数据表：

```ts
// apps/api/routers/profile.ts
import { protectedProcedure, router } from "../lib/trpc";

export const profileRouter = router({
  summary: protectedProcedure.query(({ ctx }) => ({
    id: ctx.user.id,
    name: ctx.user.name,
  })),
});
```

在 `apps/api/lib/app.ts` 导入并加入 `appRouter` 的 `profile` 属性。工作台即可通过统一客户端调用 `trpcClient.profile.summary.query()`。

## 查询模块

在 `apps/app/lib/queries/` 定义唯一查询键与查询函数，再供组件使用。不要在多个页面各自创建不同键读取同一份数据。

变更使用 `.mutation()`，成功后刷新受影响查询。输入通过 Zod 校验；私有操作默认不重试，只有业务已具备幂等键时才能考虑自动重试。

## 数据与权限

按 `ctx.user.id` 或已校验组织范围过滤数据。组织账单、积分、权限及写后读用 `ctx.db`，不使用缓存连接。资源不存在与不可见如何返回，要避免泄露他人资源是否存在。

## 验证

使用私有路由调用测试合法输入、未登录和越权。涉及唯一约束、积分和事务时使用 PGlite 测试真实数据库语义，见 [测试与排查](../testing.md)。
