API Routing
Relevant source files
The following files were used as context for generating this wiki page:
The API routing system is built upon the oRPC framework, providing a type-safe, contract-first approach to defining and handling API endpoints. The architecture is modular, with a main router that aggregates functionality from specialized sub-routers, such as those for authentication and data models (e.g., "planets"). This structure promotes separation of concerns and reusability.
Requests are processed through Hono middleware, which then passes them to oRPC handlers. These handlers match incoming requests to the defined router procedures, execute the corresponding logic (including any middleware like database context injection), and return a typed response. The entire system is defined by a shared contract, ensuring type safety between the client and server.
Core Architecture
The API's routing is centralized in a main router object, which is constructed by merging smaller, feature-specific routers. This modular design allows for clean separation of API concerns.
The following diagram illustrates how the main router is composed from the auth and planet sub-routers.
Sources: apps/api/src/router/index.ts:5-7
Main Router
The main router is initialized using createRouter from @orpc/server. It then uses the .merge() method to namespace and combine the auth and planet routers. This creates a unified routing table that the oRPC handlers can use to resolve incoming requests.
// apps/api/src/router/index.ts
import { createRouter } from "@orpc/server";
import { authRouter } from "./auth";
import { planetRouter } from "./planet";
export const router = createRouter()
.merge("auth", authRouter)
.merge("planet", planetRouter);
export type AppRouter = typeof router;
Sources: apps/api/src/router/index.ts:1-8
Request Handling
Incoming HTTP requests are handled by the Hono web framework. Specific middleware functions, handleOpenAPIRequests and handleRPCRequests, are responsible for delegating requests to the oRPC system. These handlers use the main router to match and execute procedures.
This diagram shows the lifecycle of an incoming request through the Hono middleware to an oRPC procedure.
Sources: apps/api/src/handlers/orpc.ts:37-48
The handlers are responsible for creating the context object that is passed to every procedure. This context can include authentication information (user, session) retrieved from the Hono context.
// apps/api/src/handlers/orpc.ts:40-45
export async function handleRPCRequests(c: Context, next: Next) {
const { matched, response } = await rpcHandler.handle(c.req.raw, {
prefix: "/rpc",
context: {
user: c.get("user"),
session: c.get("session"),
},
});
//...
Sources: apps/api/src/handlers/orpc.ts:37-45
Sub-Routers
Planet Router
The planetRouter defines CRUD-like operations for a "planet" resource. It demonstrates the use of oRPC procedures, input/output validation with Zod schemas from the contract package, and procedure-level middleware.
Sources: apps/api/src/router/planet.ts
Middleware
The planetRouter applies the dbProviderMiddleware to all its procedures. This middleware is responsible for injecting a db object into the procedure's context, which provides methods for interacting with the database (in this case, a fake in-memory database).
// apps/api/src/router/planet.ts:8
export const planetRouter = createRouter()
.middleware(dbProviderMiddleware)
// ... procedures
Sources: apps/api/src/router/planet.ts:8, apps/api/src/middlewares/db.ts:15-27
Procedures
The following table summarizes the procedures available under the planet namespace.
| Procedure | Description | Input Schema | Output Schema |
|---|---|---|---|
list | Retrieves a paginated list of planets. | ListPlanetsInput | ListPlanetsOutput |
get | Retrieves a single planet by its ID. | GetPlanetInput | Planet |
create | Creates a new planet. | NewPlanet | Planet |
update | Updates an existing planet. | UpdatePlanet | Planet |
Sources: apps/api/src/router/planet.ts:9-56
create Procedure Flow
The sequence diagram below shows the flow for creating a new planet. It highlights the interaction between the oRPC handler, the dbProviderMiddleware, and the final resolver logic.
Auth Router
The authRouter integrates authentication endpoints into the API. It leverages the better-auth library and its oRPC plugin to expose procedures for authentication and session management.
The auth object is configured in apps/api/src/lib/auth.ts with a Drizzle adapter and an OpenAPI plugin. The authRouter simply exposes the pre-configured oRPC procedures from this object.
// apps/api/src/router/auth.ts
import { createRouter } from "@orpc/server";
import { auth } from "../lib/auth";
export const authRouter = createRouter().merge(auth.orpc);
Sources: apps/api/src/router/auth.ts:1-4, apps/api/src/lib/auth.ts:5-19