Skip to main content
Version: 6.x

Vest with tRPC

tRPC accepts Standard Schema validators in its procedure input parser. This example uses a real router and in-process caller, so invalid data is rejected before the procedure and Vest's parsed output reaches valid procedures.

Installation​

npm install vest @trpc/server

The compatibility workspace pins @trpc/server 11.18.0 and imports only public package entry points.

Implementation example​

This source is exercised by the runtime and compile-time checks in the local compatibility workspace.

import { initTRPC, type inferRouterInputs } from '@trpc/server';
import { create, enforce, test } from 'vest';

const accountSchema = enforce.shape({
email: enforce.isString().trim().toLower(),
profile: enforce.shape({ age: enforce.isNumeric().toNumber() }),
});

const usernameSchema = enforce.shape({
username: enforce.isString().trim(),
});

export const accountSuite = create(data => {
test('profile.age', 'Must be at least 18', () => {
enforce(Number(data.profile.age)).greaterThanOrEquals(18);
});
test('email', 'Use an example.com email', () => {
enforce(data.email.trim().toLowerCase()).endsWith('@example.com');
});
}, accountSchema);

const trpc = initTRPC.create();

export const appRouter = trpc.router({
createAccount: trpc.procedure.input(accountSuite).mutation(({ input }) => ({
account: input,
accepted: true as const,
})),
});

export type AppRouter = typeof appRouter;

export async function createAccount(
input: inferRouterInputs<AppRouter>['createAccount'],
) {
return appRouter.createCaller({}).createAccount(input);
}

export function createAsyncRouter(
isAvailable: (username: string) => Promise<boolean>,
) {
const usernameSuite = create(data => {
test('username', 'Username is already taken', async () => {
enforce(await isAvailable(data.username)).isTruthy();
});
}, usernameSchema);

return trpc.router({
reserveUsername: trpc.procedure
.input(usernameSuite)
.mutation(({ input }) => input),
});
}

Tested versions​

  • Vest 6.3.2
  • @trpc/server 11.18.0

Proven capabilities​

  • asynchronous
  • input inference
  • multiple issues
  • nested paths
  • output inference
  • synchronous
  • transformed output

Runtime tests, compile-time inference tests, and the browser build run through yarn integrations:verify.

Known limitations​

  • Procedure input parsing validates complete payloads and does not expose Vest stateful interaction features.
  • tRPC wraps Standard Schema failures in a BAD_REQUEST error.

Upstream status​

No upstream change has been created. This page and the local workspace are the Vest-owned proof.