Getting started
A router, a handler that serves it, and a client that calls it with the router's types.
On this page
A router is a plain object of procedures. A handler serves it; a client calls it with the router's type.
pnpm add @trpc12/trpc effectnpm install @trpc12/trpc effectyarn add @trpc12/trpc effectbun add @trpc12/trpc effecteffect is a peer dependency, so your app and @trpc12/trpc share one copy; code that uses Promises never imports it (Packages).
.input() takes any Standard Schema (zod, Valibot, ArkType, …) or an Effect Schema (Input and output). This page uses zod:
pnpm add zodnpm install zodyarn add zodbun add zodDefine a router
import { function createFetchHandler<TRouter extends AnyRouter, TPlatform = undefined>(opts: FetchHandlerOptions<TRouter, TPlatform>): FetchHandler<TPlatform>createFetchHandler, function error<const TCode extends string, TData = undefined>(opts: Omit<TrpcErrorOptions<TCode, TData>, "defined">): TrpcError<TCode, TData>error, function initTrpc<TConfig extends RootConfig = {}>(opts?: RootOptions<TConfig["meta"] extends object ? TConfig["meta"] : {}>): TrpcRoot<TConfig["ctx"] extends object ? TConfig["ctx"] : {}, TConfig["meta"] extends object ? TConfig["meta"] : {}>initTrpc } from '@trpc12/trpc/server';
import { import zz } from 'zod';
const const t: TrpcRoot<{
user: string | null;
}, {}, RootDef<{
user: string | null;
}, {}>>
t = initTrpc<{
ctx: {
user: string | null;
};
}>(opts?: RootOptions<{}>): TrpcRoot<{
user: string | null;
}, {}, RootDef<{
user: string | null;
}, {}>>
initTrpc<{ ctx: {
user: string | null;
}
ctx: { user: string | nulluser: string | null } }>();
export const const appRouter: {
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
};
}
appRouter = {
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
}
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>
byId: const t: TrpcRoot<{
user: string | null;
}, {}, RootDef<{
user: string | null;
}, {}>>
t.TrpcRoot<{ user: string | null; }, {}, RootDef<{ user: string | null; }, {}>>.procedure: ProcedureBuilder<RootDef<{
user: string | null;
}, {}>>
procedure
.ProcedureBuilder<RootDef<{ user: string | null; }, {}>>.input<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>(schema: z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>): ProcedureBuilder<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>> (+1 overload)
input(import zz.function object<{
id: z.ZodString;
}>(shape?: {
id: z.ZodString;
} | undefined, params?: string | {
error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueInvalidType<unknown> | z.core.$ZodIssueUnrecognizedKeys>> | undefined;
message?: string | undefined | undefined;
} | undefined): z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>
object({ id: z.ZodStringid: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string() }))
.ProcedureBuilder<InputDef<RootDef<{ user: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>>.query<Post | TrpcError<"NOT_FOUND", undefined>>(resolver: (opts: ResolverOpts<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>>) => Post | TrpcError<"NOT_FOUND", undefined>): Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>
query(
(opts: ResolverOpts<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>>
opts) => const db: {
post: {
find: (id: string) => Post | undefined;
list: () => Post[];
create: (input: {
title: string;
author?: string | null;
}) => Post;
};
}
db.post: {
find: (id: string) => Post | undefined;
list: () => Post[];
create: (input: {
title: string;
author?: string | null;
}) => Post;
}
post.find: (id: string) => Post | undefinedfind(opts: ResolverOpts<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>>
opts.ResolverOpts<InputDef<RootDef<{ user: string | null; }, {}>, ZodObject<{ id: ZodString; }, $strip>>>.input: {
id: string;
}
input.id: stringid) ?? error<"NOT_FOUND", undefined>(opts: Omit<TrpcErrorOptions<"NOT_FOUND", undefined>, "defined">): TrpcError<"NOT_FOUND", undefined>error({ code: "NOT_FOUND"code: 'NOT_FOUND' }),
),
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>
create: const t: TrpcRoot<{
user: string | null;
}, {}, RootDef<{
user: string | null;
}, {}>>
t.TrpcRoot<{ user: string | null; }, {}, RootDef<{ user: string | null; }, {}>>.procedure: ProcedureBuilder<RootDef<{
user: string | null;
}, {}>>
procedure
.ProcedureBuilder<RootDef<{ user: string | null; }, {}>>.input<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>(schema: z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>): ProcedureBuilder<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>> (+1 overload)
input(import zz.function object<{
title: z.ZodString;
}>(shape?: {
title: z.ZodString;
} | undefined, params?: string | {
error?: string | z.core.$ZodErrorMap<NonNullable<z.core.$ZodIssueInvalidType<unknown> | z.core.$ZodIssueUnrecognizedKeys>> | undefined;
message?: string | undefined | undefined;
} | undefined): z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>
object({ title: z.ZodStringtitle: import zz.function string(params?: string | z.core.$ZodStringParams): z.ZodString (+1 overload)string()._ZodString<$ZodStringInternals<string>>.min(minLength: number, params?: string | z.core.$ZodCheckMinLengthParams): z.ZodStringmin(1) }))
.ProcedureBuilder<InputDef<RootDef<{ user: string | null; }, {}>, ZodObject<{ title: ZodString; }, $strip>>>.mutation<Post>(resolver: (opts: ResolverOpts<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>>) => Post): Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>
mutation((opts: ResolverOpts<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>>
opts) =>
const db: {
post: {
find: (id: string) => Post | undefined;
list: () => Post[];
create: (input: {
title: string;
author?: string | null;
}) => Post;
};
}
db.post: {
find: (id: string) => Post | undefined;
list: () => Post[];
create: (input: {
title: string;
author?: string | null;
}) => Post;
}
post.create: (input: {
title: string;
author?: string | null;
}) => Post
create({ ...opts: ResolverOpts<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>>
opts.ResolverOpts<InputDef<RootDef<{ user: string | null; }, {}>, ZodObject<{ title: ZodString; }, $strip>>>.input: {
title: string;
}
input, author?: string | null | undefinedauthor: opts: ResolverOpts<InputDef<RootDef<{
user: string | null;
}, {}>, z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>>
opts.ResolverOpts<InputDef<RootDef<{ user: string | null; }, {}>, ZodObject<{ title: ZodString; }, $strip>>>.ctx: {
user: string | null;
}
ctx.user: string | nulluser }),
),
},
};
export type type AppRouter = {
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
};
}
AppRouter = typeof const appRouter: {
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
};
}
appRouter;
export const const handler: FetchHandler<undefined>handler = createFetchHandler<{
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
};
}, undefined>(opts: FetchHandlerOptions<...>): FetchHandler<...>
createFetchHandler({
BaseHandlerOptions<{ post: { byId: Procedure<{ type: "query"; ctx: { user: string | null; }; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{ id: ZodString; }, $strip>>; services: never; }>; create: Procedure<...>; }; }>.router: {
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
};
}
router: const appRouter: {
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<z.ZodObject<{
id: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<z.ZodObject<{
title: z.ZodString;
}, z.core.$strip>>;
services: never;
}>;
};
}
appRouter,
createContext: (opts: CreateContextOpts<undefined>) => MaybePromise<{
user: string | null;
}>
createContext: (opts: CreateContextOpts<undefined>opts) => ({
user: string | nulluser: opts: CreateContextOpts<undefined>opts.CreateContextOpts<undefined>.request: HttpServerRequestrequest.HttpIncomingMessage<HttpServerError>.headers: Headersheaders['authorization'] ?? null,
}),
});request is Effect's HttpServerRequest: headers is a record of lowercase names, and on fetch runtimes request.source is the web Request.
Serve it
handler.fetch(request) is a web-standard handler: see Adapters to serve it. On Node:
import { function createServer<Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse = typeof ServerResponse>(requestListener?: RequestListener<Request, Response>): Server<Request, Response> (+1 overload)createServer } from 'node:http';
import { import NodeHttpServerNodeHttpServer, import NodeRuntimeNodeRuntime } from '@effect/platform-node';
import { import LayerLayer } from 'effect';
import { function serve(handler: FetchLike | (FetchLike & WebSocketHandlerLike), opts?: HttpOptions): Layer.Layer<never, never, HttpServer>serve } from '@trpc12/trpc/http';
function serve(handler: FetchLike | (FetchLike & WebSocketHandlerLike), opts?: HttpOptions): Layer.Layer<never, never, HttpServer>serve(const handler: FetchHandler<undefined>handler).Pipeable.pipe<Layer.Layer<never, never, HttpServer>, Layer.Layer<never, ServeError, never>, Effect<never, ServeError, never>, void>(this: Layer.Layer<never, never, HttpServer>, ab: (_: Layer.Layer<never, never, HttpServer>) => Layer.Layer<never, ServeError, never>, bc: (_: Layer.Layer<never, ServeError, never>) => Effect<never, ServeError, never>, cd: (_: Effect<never, ServeError, never>) => void): void (+21 overloads)pipe(
import LayerLayer.const provide: <never, ServeError, HttpServer | NodeServices | HttpPlatform | Generator>(that: Layer.Layer<HttpServer | NodeServices | HttpPlatform | Generator, ServeError, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, ServeError | E2, Exclude<RIn2, HttpServer | NodeServices | HttpPlatform | Generator>> (+3 overloads)provide(import NodeHttpServerNodeHttpServer.const layer: (evaluate: LazyArg<Server>, options: NodeHttpServer.Options) => Layer.Layer<HttpServer | NodeServices | HttpPlatform | Generator, ServeError>layer(function createServer<Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse = typeof ServerResponse>(requestListener?: RequestListener<Request, Response>): Server<Request, Response> (+1 overload)createServer, { ListenOptions.port?: number | undefinedport: 3000 })),
import LayerLayer.const launch: <RIn, E, ROut>(self: Layer.Layer<ROut, E, RIn>) => Effect<never, E, RIn>launch,
import NodeRuntimeNodeRuntime.const runMain: {
(options?: {
readonly disableErrorReporting?: boolean | undefined;
readonly teardown?: Teardown | undefined;
}): <E, A>(effect: Effect<A, E>) => void;
<E, A>(effect: Effect<A, E>, options?: {
readonly disableErrorReporting?: boolean | undefined;
readonly teardown?: Teardown | undefined;
}): void;
}
runMain,
);Call it
The client imports only the type:
import {
function createTrpcClient<TSource, const TLinks extends ReadonlyArray<TrpcLink<any, RouterOf<TSource>>>>(opts: TypedClientOptions<TSource, TLinks> & DuplicateSwitchCheck<TLinks> & UnmetNeedCheck<TLinks>): TrpcClient<RouterOf<TSource>, LinksContext<TLinks>, undefined, LinksTypes<TLinks>>createTrpcClient,
function httpLink<TOpts extends HttpLinkOptions>(opts: TOpts): TrpcLink<HttpLinkDecl<TOpts>>httpLink,
function matchError<E extends AnyTrpcError, H extends ErrorHandlers<E> & { readonly [K in keyof H]: K extends keyof ErrorHandlers<E> ? unknown : never; }>(err: E, handlers: H): HandlerResult<H>matchError,
function routerType<TRouter>(): RouterType<TRouter>routerType,
function safe<T, E = unknown>(promise: PromiseLike<T> & {
readonly "~error"?: E;
}): Promise<SafeResult<T, E>>
safe,
} from '@trpc12/trpc/client';
import type { type AppRouter = {
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
};
}
AppRouter } from './server.ts';
const const client: TrpcClient<{
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
};
}, {}, undefined, LinksTypes<...>>
client = createTrpcClient<RouterType<{
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
};
}>, readonly [...]>(opts: TypedClientOptions<...>): TrpcClient<...>
createTrpcClient({
TypedClientOptions<RouterType<{ post: { byId: Procedure<{ type: "query"; ctx: { user: string | null; }; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{ ...; }, $strip>>; services: never; }>; create: Procedure<...>; }; }>, readonly [...]>.router: RouterType<{
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
};
}>
router: routerType<{
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
};
}>(): RouterType<...>
routerType<type AppRouter = {
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
};
}
AppRouter>(),
TypedClientOptions<RouterType<{ post: { byId: Procedure<{ type: "query"; ctx: { user: string | null; }; meta: {}; input: { id: string; }; output: Post; errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{ ...; }, $strip>>; services: never; }>; create: Procedure<...>; }; }>, readonly [...]>.links: readonly [TrpcLink<{
form: JsonForm;
provides: "response";
}, any>]
links: [httpLink<{
url: string;
}>(opts: {
url: string;
}): TrpcLink<{
form: JsonForm;
provides: "response";
}, any>
httpLink({ url: stringurl: 'http://localhost:3000/trpc' })],
});
const post = await const client: TrpcClient<{
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
};
}, {}, undefined, LinksTypes<...>>
client.post: ClientRouter<{
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
}, {}, undefined, LinksTypes<...>>
post.byId: {
query(input: {
id: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
id: string;
title: string;
author: string | null;
createdAt: string;
}, CallError<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}, JsonForm, never>>;
}
byId.function query(input: {
id: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
id: string;
title: string;
author: string | null;
createdAt: string;
}, CallError<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}, JsonForm, never>>
query({ id: stringid: '1' });const [const created: {
id: string;
title: string;
author: string | null;
createdAt: string;
} | undefined
created, const err: (TrpcError<"NOT_FOUND", undefined> & {
readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
readonly defined: false;
}) | ... 19 more ... | undefined
err] = await safe<{
id: string;
title: string;
author: string | null;
createdAt: string;
}, (TrpcError<"NOT_FOUND", undefined> & {
readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
readonly defined: false;
}) | ... 19 more ... | (TrpcError<...> & {
...;
})>(promise: PromiseLike<...> & {
...;
}): Promise<...>
safe(const client: TrpcClient<{
post: {
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
};
}, {}, undefined, LinksTypes<...>>
client.post: ClientRouter<{
byId: Procedure<{
type: "query";
ctx: {
user: string | null;
};
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", undefined> | SchemaValidationError<ZodObject<{
id: ZodString;
}, $strip>>;
services: never;
}>;
create: Procedure<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}>;
}, {}, undefined, LinksTypes<...>>
post.create: {
mutate(input: {
title: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
id: string;
title: string;
author: string | null;
createdAt: string;
}, CallError<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}, JsonForm, never>>;
}
create.function mutate(input: {
title: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
id: string;
title: string;
author: string | null;
createdAt: string;
}, CallError<{
type: "mutation";
ctx: {
user: string | null;
};
meta: {};
input: {
title: string;
};
output: Post;
errors: SchemaValidationError<ZodObject<{
title: ZodString;
}, $strip>>;
services: never;
}, JsonForm, never>>
mutate({ title: stringtitle: '' }));
if (const err: (TrpcError<"NOT_FOUND", undefined> & {
readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
readonly defined: false;
}) | ... 19 more ... | undefined
err) {
matchError<(TrpcError<"NOT_FOUND", undefined> & {
readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
readonly defined: false;
}) | ... 18 more ... | (TrpcError<...> & {
...;
}), {
...;
}>(err: (TrpcError<...> & {
readonly defined: false;
}) | ... 24 more ... | (TrpcError<...> & {
...;
}), handlers: {
...;
}): HandlerResult<...>
matchError(const err: (TrpcError<"NOT_FOUND", undefined> & {
readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
readonly defined: false;
}) | ... 18 more ... | (TrpcError<...> & {
...;
})
err, {
type BAD_REQUEST: (e: TrpcError<"BAD_REQUEST", SchemaInputErrorData<ZodObject<{
title: ZodString;
}, $strip>>> & {
readonly defined: true;
}) => readonly ({
readonly code: "invalid_type";
readonly expected: $ZodInvalidTypeExpected;
readonly path: readonly [] | readonly ["title"];
readonly message: string;
} | {
readonly code: "too_big";
readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
readonly maximum: string | number;
readonly inclusive?: boolean | undefined;
readonly exact?: boolean | undefined;
readonly path: readonly [] | readonly [...];
readonly message: string;
} | ... 9 more ... | {
...;
})[]
BAD_REQUEST: (e: TrpcError<...> & {
...;
}
e) => e: TrpcError<...> & {
...;
}
e.TrpcError<"BAD_REQUEST", SchemaInputErrorData<ZodObject<{ title: ZodString; }, $strip>>>.data: SchemaInputErrorData<ZodObject<{
title: ZodString;
}, $strip>>
data.issues, builtin: (e: (TrpcError<"NOT_FOUND", undefined> & {
readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
readonly defined: false;
}) | ... 17 more ... | (TrpcError<...> & {
readonly defined: false;
})) => string
builtin: (e: (TrpcError<"NOT_FOUND", undefined> & {
readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
readonly defined: false;
}) | ... 17 more ... | (TrpcError<...> & {
readonly defined: false;
})
e) => e: (TrpcError<"NOT_FOUND", undefined> & {
readonly defined: false;
}) | (TrpcError<"BAD_REQUEST", undefined> & {
readonly defined: false;
}) | (TrpcError<"PARSE_ERROR", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNSUPPORTED_PROTOCOL", undefined> & {
readonly defined: false;
}) | (TrpcError<"UNAUTHORIZED", undefined> & {
readonly defined: false;
}) | (TrpcError<"PAYMENT_REQUIRED", undefined> & {
readonly defined: false;
}) | (TrpcError<"FORBIDDEN", undefined> & {
readonly defined: false;
}) | ... 17 more ... | (TrpcError<...> & {
readonly defined: false;
})
e.Error.message: stringmessage,
});
} else {
const created: {
id: string;
title: string;
author: string | null;
createdAt: string;
}
created.id: stringid;
}routerType<AppRouter>() types the client from the router type alone, and the client also types what its links read (see The client).
safe() resolves to [data, error] instead of throwing. Once error is handled, data is the output. matchError() takes a handler for each of the procedure's errors and one for the built-in ones (network failures, aborts, crashes), and leaving one out is a type error (Errors without try/catch).
Naming
Names case acronyms as words: TrpcError, initTrpc, createTrpcClient, OpenApi…, Json….
Next steps
- Procedures: input, output and the three procedure types.
- Errors: typed errors without declaring them.
- Middleware: context, base procedures and reusable middleware.
- Migrating from v11: serve old clients while you move.