Server-side calls
Call procedures in process with createRouterClient, call() and localLink.
On this page
import { function call<TDef extends ProcedureDef>(procedure: Procedure<TDef>, input: TDef["input"], opts: CallOptions<TDef>): Promise<TDef["output"]>call, function createRouterClient<TRouter extends AnyRouter>(router: TRouter, ...[opts]: {} extends RouterClientOptions<TRouter> ? [opts?: RouterClientOptions<TRouter>] : [opts: RouterClientOptions<TRouter>]): TrpcClient<TRouter, {}, DansonForm>createRouterClient } from '@trpc12/trpc/server';
const const caller: TrpcClient<{
post: {
byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
id: ZodString;
}, $strip>>, "query", {
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}>;
services: never;
unmapped: never;
}>;
list: BuildProcedure<RootDef<Context, {}>, "query", {
output: Post[];
errors: never;
services: never;
unmapped: never;
}>;
create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
ctx: Context;
ctxAdded: {
...;
};
inputOut: Unset;
errors: TrpcError<...>;
shorts: never;
}>, ZodObject<...>>, "mutation", {
...;
}>;
};
}, {}, DansonForm>
caller = createRouterClient<{
post: {
byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
id: ZodString;
}, $strip>>, "query", {
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}>;
services: never;
unmapped: never;
}>;
list: BuildProcedure<RootDef<Context, {}>, "query", {
output: Post[];
errors: never;
services: never;
unmapped: never;
}>;
create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
ctx: Context;
ctxAdded: {
...;
};
inputOut: Unset;
errors: TrpcError<...>;
shorts: never;
}>, ZodObject<...>>, "mutation", {
...;
}>;
};
}>(router: {
post: {
byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
id: ZodString;
}, $strip>>, "query", {
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}>;
services: never;
unmapped: never;
}>;
list: BuildProcedure<RootDef<Context, {}>, "query", {
output: Post[];
errors: never;
services: never;
unmapped: never;
}>;
create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
ctx: Context;
ctxAdded: {
...;
};
inputOut: Unset;
errors: TrpcError<...>;
shorts: never;
}>, ZodObject<...>>, "mutation", {
...;
}>;
};
}, opts: RouterClientOptions<...>): TrpcClient<...>
createRouterClient(const appRouter: {
post: {
byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
id: ZodString;
}, $strip>>, "query", {
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}>;
services: never;
unmapped: never;
}>;
list: BuildProcedure<RootDef<Context, {}>, "query", {
output: Post[];
errors: never;
services: never;
unmapped: never;
}>;
create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
ctx: Context;
ctxAdded: {
...;
};
inputOut: Unset;
errors: TrpcError<...>;
shorts: never;
}>, ZodObject<...>>, "mutation", {
...;
}>;
};
}
appRouter, { ctx: {
user: User | null;
} | (() => MaybePromise<{
user: User | null;
}>)
ctx: { user: User | nulluser } });
const const post: {
id: string;
title: string;
author: string | null;
createdAt: Date;
}
post = await const caller: TrpcClient<{
post: {
byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
id: ZodString;
}, $strip>>, "query", {
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}>;
services: never;
unmapped: never;
}>;
list: BuildProcedure<RootDef<Context, {}>, "query", {
output: Post[];
errors: never;
services: never;
unmapped: never;
}>;
create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
ctx: Context;
ctxAdded: {
...;
};
inputOut: Unset;
errors: TrpcError<...>;
shorts: never;
}>, ZodObject<...>>, "mutation", {
...;
}>;
};
}, {}, DansonForm>
caller.post: ClientRouter<{
byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
id: ZodString;
}, $strip>>, "query", {
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}>;
services: never;
unmapped: never;
}>;
list: BuildProcedure<RootDef<Context, {}>, "query", {
output: Post[];
errors: never;
services: never;
unmapped: never;
}>;
create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
ctx: Context;
ctxAdded: {
...;
};
inputOut: Unset;
errors: TrpcError<...>;
shorts: never;
}>, ZodObject<...>>, "mutation", {
...;
}>;
}, {}, DansonForm, {}>
post.byId: {
query(input: {
id: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
id: string;
title: string;
author: string | null;
createdAt: Date;
}, CallError<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | InputValidationError<{
readonly code: "invalid_type";
readonly expected: $ZodInvalidTypeExpected;
readonly path: readonly [] | readonly ["id"];
readonly message: string;
} | {
readonly code: "too_big";
readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
... 4 more ...;
readonly message: string;
} | ... 9 more ... | {
...;
}>;
services: never;
}, DansonForm, never>>;
}
byId.function query(input: {
id: string;
}, opts?: CallOptions<{}> | undefined): TrpcPromise<{
id: string;
title: string;
author: string | null;
createdAt: Date;
}, CallError<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | InputValidationError<{
readonly code: "invalid_type";
readonly expected: $ZodInvalidTypeExpected;
readonly path: readonly [] | readonly ["id"];
readonly message: string;
} | {
readonly code: "too_big";
readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
... 4 more ...;
readonly message: string;
} | ... 9 more ... | {
...;
}>;
services: never;
}, DansonForm, never>>
query({ id: stringid: '1' });
await call<{
type: "query";
ctx: Context;
meta: {};
input: {
id: string;
};
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}> | InputValidationError<{
readonly code: "invalid_type";
readonly expected: $ZodInvalidTypeExpected;
readonly path: readonly [] | readonly ["id"];
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 ... | {
...;
}>;
services: never;
}>(procedure: Procedure<...>, input: {
...;
}, opts: CallOptions<...>): Promise<...>
call(const appRouter: {
post: {
byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
id: ZodString;
}, $strip>>, "query", {
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}>;
services: never;
unmapped: never;
}>;
list: BuildProcedure<RootDef<Context, {}>, "query", {
output: Post[];
errors: never;
services: never;
unmapped: never;
}>;
create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
ctx: Context;
ctxAdded: {
...;
};
inputOut: Unset;
errors: TrpcError<...>;
shorts: never;
}>, ZodObject<...>>, "mutation", {
...;
}>;
};
}
appRouter.post: {
byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<{
id: ZodString;
}, $strip>>, "query", {
output: Post;
errors: TrpcError<"NOT_FOUND", {
id: string;
}>;
services: never;
unmapped: never;
}>;
list: BuildProcedure<RootDef<Context, {}>, "query", {
output: Post[];
errors: never;
services: never;
unmapped: never;
}>;
create: BuildProcedure<InputDef<With<RootDef<Context, {}>, {
ctx: Context;
ctxAdded: {
...;
};
inputOut: Unset;
errors: TrpcError<...>;
shorts: never;
}>, ZodObject<...>>, "mutation", {
...;
}>;
}
post.byId: BuildProcedure<InputDef<RootDef<Context, {}>, ZodObject<...>>, "query", {
...;
}>
byId, { id: stringid: '1' }, { ctx: Contextctx: { Context.user: User | nulluser } });localLink({ router }) does the same inside a client's link chain. For React Server Actions, see Server Actions.
In-process calls have no HTTP request: you pass the ctx (or a function that makes it) yourself, and the handler's createContext doesn't run. To share request-reading code with the handler, keep it in a function of the request and build one: ctx: () => contextFor(HttpServerRequest.fromWeb(new Request(url, { headers }))).
In-process callers (createRouterClient, createTrpcRsc, localLink({ serializer: false })) pass values by reference, so they keep native types whatever the serializer.
Testing
Test in process with createRouterClient or localLink. @trpc12/trpc/internal/testing is a semi-public TestServer Effect layer for real-server tests (with @effect/vitest's it.layer); it has no compatibility promise.