0Pricing
tRPC End-to-End Type Safe APIs · 课时

使用 tRPC 路由器组织代码

学习使用 tRPC 路由器将 API 组织成逻辑模块,并有效合并这些模块。

使用 tRPC 路由器组织代码 是 CoddyKit 上的免费 tRPC End-to-End Type Safe APIs 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 tRPC End-to-End Type Safe APIs 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 tRPC End-to-End Type Safe APIs 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Organize Your API with Routers

As your application grows, your API can become messy. tRPC routers help you organize your API into logical, reusable modules.

Think of a router as a folder for your API endpoints. Instead of one giant file, you group related operations together.

  • Modularity: Break down complex APIs.
  • Readability: Easier to understand specific parts.
  • Scalability: Simplifies adding new features.

Defining Your First Router

In tRPC, you create a router using trpc.router(). This function comes from your tRPC instance, which we assume is set up.

A router acts as a container for your API procedures (queries and mutations). Each router can have its own set of procedures.

Here's how you might define a simple "user" router:

const userRouter = t.router({
  // Procedures will go here
});

Procedures Inside Routers

Once you have a router, you can add procedures to it. Procedures are the actual API endpoints that perform actions like fetching data (queries) or modifying data (mutations).

You attach procedures using methods like .query() or .mutation() directly to your router instance. For example, a user router might have a getById query.

const userRouter = t.router({
  getById: t.procedure
    .input(z.string())
    .query(({ input }) => {
      return { id: input, name: `User ${input}` };
    }),
});

Simple User Router in Action

Let's see a basic tRPC router for users. This example includes a minimal setup to make it runnable, focusing on the router definition.

The appRouter is our main router that will contain all others. Here, we're just setting up a single userRouter with a simple query.

// src/server/trpc.ts (simplified for example)
import { initTRPC } from '@trpc/server';
import { createExpressMiddleware } from '@trpc/server/adapters/express';
import express from 'express';

const t = initTRPC.create();

// Define a user router
const userRouter = t.router({
  getById: t.procedure
    .input((val: unknown) => {
      if (typeof val === 'string') return val;
      throw new Error('Input must be a string');
    })
    .query(({ input }) => {
      // In a real app, you'd fetch from a database
      return { id: input, name: `User ${input}` };
    }),
});

// The main app router that will merge all sub-routers
const appRouter = t.router({
  user: userRouter, // Attach the user router
});

// Export type definition for client-side
export type AppRouter = typeof appRouter;

// --- Express Server Setup (for runnable example) ---
const app = express();
app.use(
  '/trpc',
  createExpressMiddleware({
    router: appRouter,
    createContext: () => ({}),
  })
);

const server = app.listen(3000, () => {
  console.log('tRPC server listening on http://localhost:3000/trpc');
  console.log('Try visiting: http://localhost:3000/trpc/user.getById?input="123"');
});

// To stop the server and exit gracefully after a short delay
setTimeout(() => {
  console.log('Server shutting down.');
  server.close(() => {
    process.exit(0);
  });
}, 5000);

Scaling with Multiple Routers

Imagine an API for an e-commerce site. You might have operations for users, products, orders, and payments.

Putting all these into a single router would make it huge and hard to manage. Instead, you create a separate router for each logical domain:

  • userRouter for user-related tasks.
  • productRouter for product management.
  • orderRouter for order processing.

This keeps your codebase tidy and promotes better teamwork.

Combining Routers with Merge

Once you have multiple individual routers, you need a way to combine them into a single, unified API that your frontend can interact with. This is where router.merge() comes in.

You use .merge() on your main, "root" router to include all your sub-routers. This makes all procedures from the sub-routers available under a specific namespace, defined by the key you assign them to.

Merging User & Post Routers

Let's expand our example to include a postRouter and then merge it with our userRouter into a single appRouter.

Notice how we attach each sub-router to a key (e.g., user: userRouter), creating a nested structure for our API calls.

// src/server/trpc.ts (simplified for example)
import { initTRPC } from '@trpc/server';
import { createExpressMiddleware } from '@trpc/server/adapters/express';
import express from 'express';

const t = initTRPC.create();

// Define a user router
const userRouter = t.router({
  getById: t.procedure
    .input((val: unknown) => {
      if (typeof val === 'string') return val;
      throw new Error('Input must be a string');
    })
    .query(({ input }) => {
      return { id: input, name: `User ${input}` };
    }),
});

// Define a post router
const postRouter = t.router({
  getAll: t.procedure
    .query(() => {
      return [{ id: 'p1', title: 'First Post' }, { id: 'p2', title: 'Second Post' }];
    }),
  create: t.procedure
    .input((val: unknown) => {
      if (typeof val === 'object' && val !== null && 'title' in val && typeof val.title === 'string') return val as { title: string };
      throw new Error('Input must be an object with a title string');
    })
    .mutation(({ input }) => {
      return { id: `new-${Date.now()}`, title: input.title };
    }),
});

// The main app router that merges all sub-routers
const appRouter = t.router({
  user: userRouter, // Attach user router under 'user' namespace
  post: postRouter, // Attach post router under 'post' namespace
});

export type AppRouter = typeof appRouter;

// --- Express Server Setup (for runnable example) ---
const app = express();
app.use(express.json()); // For handling mutation inputs
app.use(
  '/trpc',
  createExpressMiddleware({
    router: appRouter,
    createContext: () => ({}),
  })
);

const server = app.listen(3000, () => {
  console.log('tRPC server listening on http://localhost:3000/trpc');
  console.log('Available endpoints:');
  console.log('  GET /trpc/user.getById?input="456"');
  console.log('  GET /trpc/post.getAll');
  console.log('  POST /trpc/post.create (body: {"title": "New Post"})');
});

setTimeout(() => {
  console.log('Server shutting down.');
  server.close(() => {
    process.exit(0);
  });
}, 5000);

Accessing Merged Procedures

Once routers are merged, your frontend client can access procedures using dot notation, reflecting the nested structure you defined.

  • To call a user query: client.user.getById(...)
  • To call a post query: client.post.getAll()
  • To call a post mutation: client.post.create(...)

This clear naming convention makes your API intuitive and easy to navigate.

Organizing Your Router Files

For larger projects, it's common to place each router in its own file. This keeps your codebase modular and easy to navigate.

A typical structure might look like this:

  • src/server/trpc.ts (tRPC instance, root router definition)
  • src/server/routers/user.ts (userRouter definition)
  • src/server/routers/post.ts (postRouter definition)
  • src/server/index.ts (server setup, merging routers)

Router Merging Check

You have a productRouter and an orderRouter. You want to combine them into your main appRouter so they can be accessed as client.product... and client.order....

Which code snippet correctly merges these routers?

Recap & Next Steps

You've learned how tRPC routers help organize your API into logical, manageable modules. By defining individual routers for different domains and then merging them into a root router, you create a scalable and maintainable API structure.

  • t.router(): Creates a new router.
  • Procedures: Added to routers using .query() or .mutation().
  • Merging: Combine routers into a single API by assigning them to keys in the root router definition.

Next, you'll dive deeper into implementing specific query procedures!

常见问题解答

「使用 tRPC 路由器组织代码」课时是免费的吗?

是的 — 「使用 tRPC 路由器组织代码」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 tRPC End-to-End Type Safe APIs 课程的其余内容,请升级到 CoddyKit PRO。 tRPC End-to-End Type Safe APIs 课程共包含 4 节课。

「使用 tRPC 路由器组织代码」这节课中我会学到什么?

学习使用 tRPC 路由器将 API 组织成逻辑模块,并有效合并这些模块。 你通过在浏览器中直接运行的动手代码来练习 tRPC End-to-End Type Safe APIs,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 tRPC End-to-End Type Safe APIs 需要有经验吗?

无需任何先前经验。CoddyKit 上的 tRPC End-to-End Type Safe APIs 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「使用 tRPC 路由器组织代码」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 tRPC End-to-End Type Safe APIs 课中编写并运行代码吗?

能。每节 tRPC End-to-End Type Safe APIs 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 tRPC 路由器组织代码
  2. 实现查询过程
  3. 开发变更过程
  4. 合并与嵌套路由器
← 返回 tRPC End-to-End Type Safe APIs