4.7 KiB
4.7 KiB
@repo/api -- tRPC v11 Router Definitions
Purpose
This package defines all tRPC v11 routers for the monorepo. Each router validates input with Zod and delegates execution to controllers in @repo/core. Routers are the only entry point for client-side RPC calls. They contain zero business logic.
Hard Rules
- NEVER put business logic in routers -- always delegate to a controller from
@repo/core - NEVER import from
@repo/core/infrastructureor anyapps/*package - Input validation uses Zod schemas inline on each procedure
- Each domain gets its own
{domain}.router.tsfile - Use
.query()for reads (GET-like),.mutation()for writes (POST/PUT/DELETE-like) - All procedures call exactly one controller function from
@repo/core
File Structure
packages/api/
src/
trpc.ts # tRPC initialization, exports router + publicProcedure
router/
index.ts # appRouter composition, exports AppRouter type
auth.router.ts # Auth domain: signIn, signUp, signOut
content.router.ts # Content domain: listArticles, createArticle
index.ts # Package entry: re-exports appRouter + AppRouter type
package.json
AGENTS.md
How Procedures Map to Controllers
| Procedure type | HTTP equivalent | When to use | Example |
|---|---|---|---|
.query() |
GET | Fetching/reading data | content.listArticles |
.mutation() |
POST/PATCH/DELETE | Creating, updating, deleting data | auth.signIn, content.createArticle |
Every procedure follows the same pattern:
myProcedure: publicProcedure
.input(z.object({ /* Zod schema */ }))
.query(async ({ input }) => { // or .mutation()
return await myController(input); // delegate to @repo/core controller
}),
Existing Routers
auth.router.ts
| Procedure | Type | Input | Controller |
|---|---|---|---|
signIn |
mutation | { username: string, password: string } |
signInController |
signUp |
mutation | { username: string, password: string, confirmPassword: string } |
signUpController |
signOut |
mutation | { sessionId: string } |
signOutController |
content.router.ts
| Procedure | Type | Input | Controller |
|---|---|---|---|
listArticles |
query | { status?, authorId?, limit?, offset? } (optional) |
getArticlesController |
createArticle |
mutation | { title: string, content: string, authorId: string, slug?: string } |
createArticleController |
Recipe: Adding a New tRPC Router
This example adds a comments domain router with listComments (query) and createComment (mutation).
Step 1: Create the router file
Create src/router/comments.router.ts:
import { z } from "zod";
import { router, publicProcedure } from "../trpc";
import {
getCommentsController,
createCommentController,
} from "@repo/core";
export const commentsRouter = router({
listComments: publicProcedure
.input(
z
.object({
articleId: z.string(),
limit: z.number().optional(),
offset: z.number().optional(),
})
)
.query(async ({ input }) => {
return await getCommentsController(input);
}),
createComment: publicProcedure
.input(
z.object({
articleId: z.string(),
authorId: z.string(),
body: z.string().min(1).max(2000),
})
)
.mutation(async ({ input }) => {
return await createCommentController(input);
}),
});
Step 2: Register in the appRouter
Edit src/router/index.ts:
import { router } from "../trpc";
import { authRouter } from "./auth.router";
import { contentRouter } from "./content.router";
import { commentsRouter } from "./comments.router"; // <-- add import
export const appRouter = router({
auth: authRouter,
content: contentRouter,
comments: commentsRouter, // <-- register here
});
export type AppRouter = typeof appRouter;
Step 3: Verify
The AppRouter type is automatically inferred. Any app using @repo/api-client will immediately see trpc.comments.listComments.useQuery(...) and trpc.comments.createComment.useMutation(...) with full type safety -- no code generation step needed.
Dependencies
| Dependency | Purpose |
|---|---|
@repo/core |
Controllers that contain business logic |
@trpc/server |
tRPC v11 server-side primitives |
zod |
Runtime input validation schemas |
Cross-References
- Controllers live in:
packages/core/src/interface-adapters/controllers/-- seepackages/core/AGENTS.md - Client consumption:
packages/api-client/-- seepackages/api-client/AGENTS.md - HTTP endpoint:
apps/web-next/src/app/api/trpc/[trpc]/route.tsuses the fetch adapter to serveappRouter