Skip to content

tRPC v12 isn’t on npm yet. The @trpc12/* packages on this site can’t be installed until it’s released. Use v11 today

tRPC

Lifecycle hooks

onStart, onSuccess, onError and onFinish, for logging and metrics.

On this page

@trpc12/trpc/middleware has lifecycle helpers, each an ordinary middleware:

import { function onError(fn: (error: AnyTrpcError, opts: AnyOpts) => MaybePromise<void>): MiddlewareFunction<unknown, unknown, unknown, {}, never>onError, 
function onFinish(fn: (result: {
    readonly ok: true;
    readonly data: unknown;
} | {
    readonly ok: false;
    readonly error: AnyTrpcError;
}, opts: AnyOpts) => MaybePromise<void>): MiddlewareFunction<unknown, unknown, unknown, {}, never>
onFinish
} from '@trpc12/trpc/middleware';
const
const observed: ProcedureBuilder<With<With<RootDef<Context, {}>, {
    ctx: Context;
    ctxAdded: {};
    inputOut: Unset;
    errors: never;
    shorts: never;
}>, {
    ctx: Context;
    ctxAdded: {};
    inputOut: Unset;
    errors: never;
    shorts: never;
}>>
observed
= const t: TrpcRoot<Context, {}, RootDef<Context, {}>>t.TrpcRoot<Context, {}, RootDef<Context, {}>>.procedure: ProcedureBuilder<RootDef<Context, {}>>procedure
.
ProcedureBuilder<RootDef<Context, {}>>.use<{}, never, never, Unset, object>(fn: MiddlewareFunction<{
    user: User | null;
} & object, undefined, {}, {}, never, never, Unset>): ProcedureBuilder<With<RootDef<Context, {}>, {
    ctx: Context;
    ctxAdded: {};
    inputOut: Unset;
    errors: never;
    shorts: never;
}>> (+1 overload)
use
(
function onFinish(fn: (result: {
    readonly ok: true;
    readonly data: unknown;
} | {
    readonly ok: false;
    readonly error: AnyTrpcError;
}, opts: AnyOpts) => MaybePromise<void>): MiddlewareFunction<unknown, unknown, unknown, {}, never>
onFinish
((
result: {
    readonly ok: true;
    readonly data: unknown;
} | {
    readonly ok: false;
    readonly error: AnyTrpcError;
}
result
, opts: AnyOptsopts) =>
const metrics: {
    count(path: string, ok: boolean): void;
}
metrics
.function count(path: string, ok: boolean): voidcount(opts: AnyOptsopts.MiddlewareOpts<unknown, unknown, unknown>.path: stringpath,
result: {
    readonly ok: true;
    readonly data: unknown;
} | {
    readonly ok: false;
    readonly error: AnyTrpcError;
}
result
.ok: booleanok)))
.
ProcedureBuilder<With<RootDef<Context, {}>, { ctx: Context; ctxAdded: {}; inputOut: Unset; errors: never; shorts: never; }>>.use<{}, never, never, Unset, object>(fn: MiddlewareFunction<{
    user: User | null;
} & object, undefined, {}, {}, never, never, Unset>): ProcedureBuilder<With<With<RootDef<Context, {}>, {
    ctx: Context;
    ctxAdded: {};
    inputOut: Unset;
    errors: never;
    shorts: never;
}>, {
    ctx: Context;
    ctxAdded: {};
    inputOut: Unset;
    errors: never;
    shorts: never;
}>> (+1 overload)
use
(function onError(fn: (error: AnyTrpcError, opts: AnyOpts) => MaybePromise<void>): MiddlewareFunction<unknown, unknown, unknown, {}, never>onError((err: AnyTrpcErrorerr, opts: AnyOptsopts) =>
const log: {
    warn(path: string, code: string): void;
}
log
.function warn(path: string, code: string): voidwarn(opts: AnyOptsopts.MiddlewareOpts<unknown, unknown, unknown>.path: stringpath, err: AnyTrpcErrorerr.TrpcError<string, any>.code: stringcode)));

onStart runs before the rest of the chain, onSuccess with the result when the rest succeeds (for a subscription, once the stream is set up), onError with the error when it fails, and onFinish with the outcome either way. Put them on a base procedure to cover every procedure built from it (Middleware).

For spans rather than logs, put a tracer in the handler's layer: every call already runs in a trpc.<path> span (Tracing).

Credits

The four hooks follow oRPC's onStart, onSuccess, onError and onFinish interceptors.