类型链路
这一页讲 orva 最核心的设计优势:类型不会只停留在某一个 API 边界。
这条链路是什么
在一条典型的 orva 路由里,有价值的类型链路大致是:
app.use()注入共享变量或 validated datavalidator()或zodValidator()解析请求输入- 路由 handler 从
c上读取类型化数据 c.json()定义响应体形状createRPC<typeof app>()读取请求和响应类型createOpenAPIDocument()读取同一批元数据生成文档
01
Request
统一以 Fetch API Request 进入应用,平台适配器只负责把宿主请求桥接进来。
02
Validator
json / form / query / param / header / cookie / text 输入统一进入类型安全校验链。
03
Route
Context、Middleware、路由组合保持直观,业务逻辑集中在 handler 层。
04
Contracts
校验元数据继续流向 RPC 与 OpenAPI,减少客户端、文档和运行时代码漂移。
一个完整例子
ts
import { z } from 'zod';
import { createOrva, defineMiddleware } from 'orvajs';
import { createRPC } from 'orvajs/rpc';
import { zodValidator } from 'orvajs/validator/zod';
const session = defineMiddleware<{ session: { role: string } }>(async (c, next) => {
c.set('session', { role: 'admin' });
await next();
});
const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
const app = createOrva()
.use(session)
.post(
'/users/:id',
zodValidator('json', createUserSchema),
(c) => {
const body = c.valid('json');
const role = c.get('session')?.role;
return c.json({
id: c.params.id,
role,
user: body,
}, 201);
},
);
const rpc = createRPC<typeof app>({
baseURL: 'https://api.example.com',
});js
import { z } from "zod";
import { createOrva, defineMiddleware } from "orvajs";
import { createRPC } from "orvajs/rpc";
import { zodValidator } from "orvajs/validator/zod";
const session = defineMiddleware(async (c, next) => {
c.set("session", { role: "admin" });
await next();
});
const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email()
});
const app = createOrva().use(session).post(
"/users/:id",
zodValidator("json", createUserSchema),
(c) => {
const body = c.valid("json");
const role = c.get("session")?.role;
return c.json({
id: c.params.id,
role,
user: body
}, 201);
}
);
const rpc = createRPC({
baseURL: "https://api.example.com"
});链路里分别流动了什么
app.use()
defineMiddleware() 可以把类型化变量推入后续路由。
这样 c.get('session') 就不是松散挂载的状态,而是有静态类型的上下文。
validator 输出
zodValidator('json', schema) 会把请求体解析结果变成 handler 的类型化输入。
所以 c.valid('json') 不只是运行时 helper,而是一条契约边界。
路由响应
当你返回 c.json(...) 时,响应体类型会被保留下来。
即使没有额外写 OpenAPI 响应声明,RPC 侧也能直接读到这部分类型。
RPC 请求与响应
对 createRPC<typeof app>() 来说:
body会从 validator 输出推导param会从路径参数推导json()和value()会从c.json(...)或路由元数据推导
OpenAPI 输出
当你再补充路由元数据或 schema-aware validator 时,同一条路由还能继续产出 OpenAPI 定义,而不需要再写一套重复契约。
这件事为什么重要
如果没有这条链路,团队通常要在四个地方重复描述同一个接口:
- 运行时校验
- handler 类型
- 客户端类型
- API 文档
orva 的目标就是让这些层尽量靠近,减少漂移。