Back to Trpc

Define Routers

www/docs/server/routers.md

11.16.04.2 KB
Original Source

To begin building your tRPC-based API, you'll first need to define your router. Once you've mastered the fundamentals, you can customize your routers for more advanced use cases.

Initialize tRPC

You should initialize tRPC exactly once per application. Multiple instances of tRPC will cause issues.

ts
// @filename: trpc.ts
// ---cut---
import { initTRPC } from '@trpc/server';

// You can use any variable name you like.
// We use t to keep things simple.
const t = initTRPC.create();

export const router = t.router;
export const publicProcedure = t.procedure;

You'll notice we are exporting certain methods of the t variable here rather than t itself. This is to establish a certain set of procedures that we will use idiomatically in our codebase.

Defining a router

Next, let's define a router with a procedure to use in our application. We have now created an API "endpoint".

In order for these endpoints to be exposed to the frontend, your Adapter should be configured with your appRouter instance.

ts
// @filename: trpc.ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();

export const publicProcedure = t.procedure;
export const router = t.router;

// @filename: _app.ts
import * as trpc from '@trpc/server';
// ---cut---
import { publicProcedure, router } from './trpc';

const appRouter = router({
  greeting: publicProcedure.query(() => 'hello tRPC v11!'),
});

// Export only the type of a router!
// This prevents us from importing server code on the client.
export type AppRouter = typeof appRouter;

Defining an inline sub-router {#inline-sub-router}

When you define an inline sub-router, you can represent your router as a plain object.

In the below example, nested1 and nested2 are equal:

ts
// @filename: trpc.ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();


export const middleware = t.middleware;
export const publicProcedure = t.procedure;
export const router = t.router;

// @filename: _app.ts
// ---cut---
import * as trpc from '@trpc/server';
import { publicProcedure, router } from './trpc';

const appRouter = router({
  // Using the router() method
  nested1: router({
    proc: publicProcedure.query(() => '...'),
  }),
  // Using an inline sub-router
  nested2: {
    proc: publicProcedure.query(() => '...'),
  },
});

Advanced usage

When initializing your router, tRPC allows you to:

You can use method chaining to customize your t-object on initialization. For example:

ts
import { initTRPC } from '@trpc/server';

type Context = { userId: string };
type Meta = { description: string };

// ---cut---
const t = initTRPC.context<Context>().meta<Meta>().create({
  /* [...] */
});

Runtime Configuration

ts
type DataTransformerOptions = any;
type ErrorFormatter = any;
// ---cut---
interface RootConfig {
  /**
   * Use a data transformer
   * @see https://trpc.io/docs/v11/data-transformers
   */
  transformer: DataTransformerOptions;

  /**
   * Use custom error formatting
   * @see https://trpc.io/docs/v11/error-formatting
   */
  errorFormatter: ErrorFormatter;

  /**
   * Allow `@trpc/server` to run in non-server environments
   * @warning **Use with caution**, this should likely mainly be used within testing.
   * @default false
   */
  allowOutsideOfServer: boolean;

  /**
   * Is this a server environment?
   * @warning **Use with caution**, this should likely mainly be used within testing.
   * @default typeof window === 'undefined' || 'Deno' in window || process.env.NODE_ENV === 'test'
   */
  isServer: boolean;

  /**
   * Is this development?
   * Will be used to decide if the API should return stack traces
   * @default process.env.NODE_ENV !== 'production'
   */
  isDev: boolean;
}