@aipt/api-contract
v0.2.4
Published
与传输无关的 API 请求、响应和错误合同。
Readme
API Contract
@aipt/[email protected] 让一份端点定义同时产出类型、运行时校验和 mock。契约声明一次,客户端调用、服务端处理和开发期 mock 共用同一个 schema,三者无法互相漂移。
本包不依赖任何具体校验器。它消费 Standard Schema 规范,因此 zod、valibot、arktype 都可直接作为 schema 传入;平台不锁定其中任何一个。本包也不含 React、HTTP 框架、Provider SDK 或产品领域类型。
安装与导入
pnpm add @aipt/[email protected]import { createApiClient, createRouteHandler, defineEndpoint } from "@aipt/api-contract";
import { fetchTransport } from "@aipt/api-contract/fetch";最小用法
import { z } from "zod";
const readStation = defineEndpoint({
operationId: "weather.readStation",
method: "GET",
path: "/stations/:stationId/latest",
params: z.object({ stationId: z.string().min(1) }),
response: z.object({ reading: z.object({ celsius: z.number() }) }),
});
// 客户端:返回判别联合,不抛业务异常
const client = createApiClient({ baseUrl: "https://api.example", endpoints: { readStation }, transport: fetchTransport(), timeoutMs: 10_000 });
const result = await client.readStation({ params: { stationId: "PEK001" } });
if (result.ok) console.log(result.data.reading.celsius); // number
else console.log(result.error.code);
// 服务端:同一个定义,输入自动校验,输出必须符合契约
const handler = createRouteHandler(readStation, ({ params }) => ({ reading: { celsius: latestOf(params.stationId) } }));开发期把 transport 换成 mock,其余代码一行不改:
import { createMockTransport } from "@aipt/api-contract";
const transport = createMockTransport({
endpoints: { readStation },
handlers: { readStation: () => ({ reading: { celsius: 21.5 } }) },
});mock 返回值同样经过端点的 response schema 校验,mock 数据无法偏离契约。
错误与边界
API_ENDPOINT_INVALID:端点定义非法(非法 operationId、路径穿越、GET 携带 body、路径参数与paramsschema 不匹配)。装配期即失败。API_INPUT_INVALID:params/query/body不符合 schema。客户端不发出请求;服务端回落为 fail 信封。API_RESPONSE_INVALID:响应载荷不符合responseschema。服务端漂移在此 fail closed,业务拿不到半截数据。API_ENVELOPE_INVALID:响应不是合法信封。API_TRANSPORT_FAILED:传输层失败、取消或超时。API_TIMEOUT_INVALID:deadline 不是正数。API_MOCK_UNHANDLED:mock 未登记该端点,不静默返回空数据。
其他边界:
- 线格式为
{ ok: true, ...载荷 }/{ ok: false, error: { code, message } },与既有服务端一致。 - 失败信封是数据(
result.ok === false),只有契约违例和传输故障才抛异常。 - 服务端输出非法时抛出而非回落——那是服务端缺陷,绝不把不符合契约的数据发出去。
- 每次调用必须有正数 deadline,可与调用方
AbortSignal组合。 - 中间件为洋葱模型,失败用普通
try/catch观察,不需要独立错误通道。 - 不记录请求体、响应体、Header 或 Secret。
与服务端状态层的关系
本包只负责契约与传输,不做缓存、去重、重试或失效。客户端产出的 (input) => Promise<ApiResult<T>> 可直接作为 TanStack Query 的 queryFn,两者组合而非替代。
退出方式
端点定义是纯数据,schema 由调用方拥有。替换 createApiClient 与 createRouteHandler 后删除依赖即可;本包不持有持久状态,也不拥有任何已发出的请求。
