Raypx

API 概览

基于 oRPC 的类型安全 API 层,集成 Zod 校验。

Raypx 使用 oRPC 构建类型安全的 API 层。oRPC 是一个轻量级的 RPC 框架,与 Zod 深度集成,提供端到端的类型推导——从服务端到客户端,无需手动定义类型。

入口

所有 RPC 请求通过 TanStack Start 文件路由 src/routes/api/rpc/$ 处理:

export const Route = createFileRoute("/api/rpc/$")({
  server: {
    handlers: {
      HEAD: handle,
      GET: handle,
      POST: handle,
      PUT: handle,
      PATCH: handle,
      DELETE: handle,
    },
  },
})

双处理器

API 路由注册了两个处理器,共享同一个路由器(appRouter):

  1. RPCHandler——处理 RPC 调用,前缀为 /api/rpc
  2. OpenAPIHandler——处理 OpenAPI 文档请求,前缀为 /api/rpc/api-reference
const rpcHandler = new RPCHandler(appRouter, {
  interceptors: [
    onError((error) => {
      logger.error("rpc.error", { feature: "rpc", error: serializeError(error) })
    }),
  ],
})

const apiHandler = new OpenAPIHandler(appRouter, {
  plugins: [
    new OpenAPIReferencePlugin({
      schemaConverters: [new ZodToJsonSchemaConverter()],
    }),
  ],
})

请求先经过 RPCHandler,如果没有匹配的 RPC 路由,再交给 OpenAPIHandler 处理。

Context 创建

每个请求都会创建一个 Context 对象,包含当前用户的会话信息:

// packages/rpc/src/context.ts
import { auth } from "@raypx/auth"

export async function createContext({ req }: { req: Request }) {
  const session = await auth.api.getSession({
    headers: req.headers,
  })
  return { session }
}

export type Context = Awaited<ReturnType<typeof createContext>>

Context 通过 oRPC 的类型系统传递到每个 Procedure 的 handler 中。

路由器结构

appRouter 是所有 RPC Procedure 的根路由器:

// packages/rpc/src/routers/index.ts
export const appRouter = {
  healthCheck: publicProcedure.handler(async () => { /* ... */ }),
  privateData: protectedProcedure.handler(({ context }) => { /* ... */ }),

  profile: profileRouter,
  documents: documentRouter,
  conversations: conversationRouter,
  usage: usageRouter,
}
路由器说明认证
healthCheck健康检查(数据库 + 存储)公开
privateData测试用受保护端点受保护
profile用户资料管理受保护
documents文档管理受保护
conversations对话管理受保护
usage使用量统计受保护

公开与受保护 Procedure

oRPC 使用 middleware 实现认证区分:

  • publicProcedure——无需认证,任何人都可以调用
  • protectedProcedure——需要有效的用户会话,否则返回 UNAUTHORIZED 错误
export const publicProcedure = o

const requireAuth = o.middleware(async ({ context, next }) => {
  if (!context.session?.user) {
    throw new ORPCError("UNAUTHORIZED")
  }
  return next({ context: { session: context.session } })
})

export const protectedProcedure = publicProcedure.use(requireAuth)

OpenAPI 文档

通过 OpenAPIReferencePlugin 插件,oRPC 自动将路由器转换为 OpenAPI 文档,可以通过以下地址访问:

GET /api/rpc/api-reference

Zod Schema 通过 ZodToJsonSchemaConverter 自动转换为 JSON Schema,用于文档中的请求/响应类型描述。

接下来

On this page