关于 orpc-fullstack
面向使用 oRPC 构建 TypeScript API 的开发者,提供契约、过程、路由、中间件和客户端的实践指南。内容还涉及 Hono、TanStack Query、实时事件与错误处理。
主要功能
- 01契约优先的 API 开发
- 02输入输出验证与中间件
- 03类型化错误处理
- 04Hono 服务端集成
- 05TanStack Query 数据获取
- 06SSE 与事件迭代器
适用场景
- 01按契约实现 API 路由
- 02为过程添加身份验证和授权
- 03通过 TanStack Query 获取数据
- 04构建 SSE 流式功能
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ stephen-golban/ orpc-fullstack --skill orpc-fullstack安装后在 Claude Code 中输入/orpc-fullstack确认已加载。
附带文件references/REFERENCE.md
详细介绍
oRPC — 轻松构建类型安全的 API
oRPC 将 RPC 与 OpenAPI 相结合,提供端到端类型安全的 API(v1.12+)。它支持 Zod、Valibot、Arktype 或任何 Standard Schema 库。
适用场景
在以下情况参考这些指南:
- 创建或修改 API 过程(契约、路由器、处理程序)
- 设置中间件(身份验证、授权守卫、日志记录)
- 将 oRPC 与 Hono 或其他服务端框架集成
- 使用 TanStack Query 构建数据获取钩子
- 使用事件迭代器 / SSE 实现实时功能
- 配置客户端链接(fetch、WebSocket、批处理、重试)
- 处理错误(服务端 ORPCError、客户端类型化错误)
核心概念
| 概念 | 导入项 | 用途 |
|---|---|---|
| 契约 | @orpc/contract 中的 oc | 定义 API 结构,无需处理程序 |
| 过程 | @orpc/server 中的 os | 结合验证、中间件和 DI 的函数 |
| 路由器 | 普通对象 | 将过程组合成树状结构 |
| 中间件 | os.middleware() | 拦截请求、注入上下文、限制访问 |
| 处理程序 | OpenAPIHandler / RPCHandler | 通过 HTTP/WS 提供过程 |
| 客户端 | createORPCClient + 链接 | 根据契约 / 路由器创建类型安全的客户端 |
| TanStack Query | createTanstackQueryUtils | 用于查询 / 修改操作的 React 钩子 |
项目结构
按领域模块组织,并为每个模块配对契约与路由器文件:
src/
index.ts # Hono app + handler setup
middlewares/
auth-middleware.ts # Session validation -> injects user
modules/
contract.ts # Root barrel: all contracts
router.ts # Root barrel: all routers
health/
health.contract.ts
health.router.ts
user/
user.contract.ts
user.router.ts
根目录的 barrel 文件组合各模块:export default { health, user }。
契约优先开发
契约定义 API 结构。路由器通过 TypeScript 强制检查来实现契约。
// Contract — define shape
import { oc } from "@orpc/contract";
import { z } from "zod/v4";
const userContract = oc
.route({ tags: ["user"] })
.errors({ UNAUTHORIZED: {} });
const searchUser = userContract
.route({ method: "POST", path: "/user/search" })
.input(z.object({ query: z.string() }))
.output(z.array(userSchema));
export default { searchUser };
// Router — implement contract
import { implement } from "@orpc/server";
import contract from "./user.contract";
const router = implement(contract).$context<{ headers: Headers }>();
const searchUser = router.searchUser
.use(authMiddleware)
.handler(async ({ input, context }) => { /* ... */ });
export default { searchUser };
过程
import { os } from "@orpc/server";
const example = os
.use(aMiddleware) // Middleware
.input(z.object({ name: z.string() })) // Validate input
.output(z.object({ id: z.number() })) // Validate output (recommended)
.handler(async ({ input, context }) => { // Handler
return { id: 1 };
});
.handler是唯一必需的步骤- 指定
.output可提高 TypeScript 类型推断速度 - 创建可复用的基础过程:
const protectedProcedure = os.$context<Ctx>().use(authMiddleware)
中间件
身份验证中间件会将用户注入上下文:
export const authMiddleware = os
.$context<{ headers: Headers }>()
.middleware(async ({ context, next }) => {
const session = await auth.api.getSession({ headers: context.headers });
if (!session) throw new ORPCError("UNAUTHORIZED");
return next({ context: { ...context, user: session.user } });
});
用于授权守卫的输入感知型中间件:
export const membershipGuard = os
.$context<{ user: User }>()
.middleware(async ({ context, next }, input: { uuid: string }) => {
// Check membership using input.uuid + context.user.id
if (!member) throw new ORPCError("FORBIDDEN");
return next();
});
中间件按从左到右的顺序堆叠:.use(auth).use(guard).handler(...)。
内置中间件:onStart、onSuccess、onError、onFinish、dedupeMiddleware。
错误处理
// Server — throw errors
throw new ORPCError("NOT_FOUND");
throw new ORPCError("BAD_REQUEST", { message: "Invalid input" });
// Contract-defined typed errors
const contract = oc.errors({
RATE_LIMITED: { data: z.object({ retryAfter: z.number() }) },
});
// Handler uses typed factory
const proc = implement(contract).handler(async ({ errors }) => {
throw errors.RATE_LIMITED({ data: { retryAfter: 60 } });
});
// Client — handle errors
const [error, data] = await safe(client.doSomething({ id: "123" }));
if (isDefinedError(error)) { /* typed from contract */ }
Hono 集成
import { OpenAPIHandler } from "@orpc/openapi/fetch";
import { Hono } from "hono";
const handler = new OpenAPIHandler(router, { /* plugins, interceptors */ });
const app = new Hono()
.basePath("/api")
.use("/rpc/*", async (c, next) => {
const { matched, response } = await handler.handle(c.req.raw, {
prefix: "/api/rpc",
context: { headers: c.req.raw.headers },
});
if (matched) return c.newResponse(response.body, response);
await next();
});
TanStack Query
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
const orpc = createTanstackQueryUtils(client);
// Queries
useQuery(orpc.user.search.queryOptions({ input: { query } }));
// Mutations
useMutation(orpc.vehicle.add.mutationOptions());
// Infinite queries
useInfiniteQuery(orpc.feed.list.infiniteOptions({
input: (pageParam) => ({ cursor: pageParam, limit: 20 }),
initialPageParam: undefined,
getNextPageParam: (lastPage) => lastPage.nextCursor,
}));
// Keys for invalidation
orpc.vehicle.key() // All vehicle queries
queryClient.invalidateQueries({ queryKey: orpc.vehicle.key() });
事件迭代器(SSE / 流式传输)
// Server — async generator
const live = os
.output(eventIterator(z.object({ message: z.string() })))
.handler(async function* ({ signal }) {
for await (const payload of publisher.subscribe("topic", { signal })) {
yield payload;
}
});
// Client — consume
for await (const event of await client.live()) {
console.log(event.message);
}
使用 EventPublisher 在处理程序之间实现类型化的发布 / 订阅。
客户端设置
import { RPCLink } from "@orpc/client/fetch";
import { createORPCClient } from "@orpc/client";
const link = new RPCLink({
url: "http://localhost:3000/api/rpc",
headers: () => ({ Authorization: `Bearer ${getToken()}` }),
});
export const client = createORPCClient(link);
WebSocket:import { RPCLink } from "@orpc/client/websocket"。
详细参考
有关完整示例、高级模式和完整 API 内容,请参阅:
- 完整参考 — 完整文档,包含详细代码示例,涵盖契约、路由器、中间件、服务端处理程序、客户端设置、TanStack Query、事件迭代器、插件、文件上传、WebSocket、AI SDK 集成和元数据。
评论
支持 Markdown