跳至主内容
版本:10.x

Fastify 适配器

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

示例应用

要开始使用 Fastify 适配器,最好的方式是查看示例应用。

DescriptionLinks
  • Fastify server with WebSocket
  • Simple tRPC client in node

在 Fastify 中使用 tRPC

安装依赖

bash
yarn add @trpc/server fastify zod
bash
yarn add @trpc/server fastify zod

Zod 并非必需依赖,但下方示例路由中会使用到。

创建路由器

首先需要创建路由来处理查询、变更和订阅操作。

下面提供了示例路由器,将其保存为 router.ts 文件:

router.ts
router.ts
ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
type User = {
id: string;
name: string;
bio?: string;
};
const users: Record<string, User> = {};
export const t = initTRPC.create();
export const appRouter = t.router({
getUserById: t.procedure.input(z.string()).query((opts) => {
return users[opts.input]; // input type is string
}),
createUser: t.procedure
.input(
z.object({
name: z.string().min(3),
bio: z.string().max(142).optional(),
}),
)
.mutation((opts) => {
const id = Date.now().toString();
const user: User = { id, ...opts.input };
users[user.id] = user;
return user;
}),
});
// export type definition of API
export type AppRouter = typeof appRouter;
router.ts
ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
type User = {
id: string;
name: string;
bio?: string;
};
const users: Record<string, User> = {};
export const t = initTRPC.create();
export const appRouter = t.router({
getUserById: t.procedure.input(z.string()).query((opts) => {
return users[opts.input]; // input type is string
}),
createUser: t.procedure
.input(
z.object({
name: z.string().min(3),
bio: z.string().max(142).optional(),
}),
)
.mutation((opts) => {
const id = Date.now().toString();
const user: User = { id, ...opts.input };
users[user.id] = user;
return user;
}),
});
// export type definition of API
export type AppRouter = typeof appRouter;

若路由文件过大,可将其拆分为多个独立文件实现的子路由,然后合并为单一根路由 appRouter

创建上下文

接着需要为每个请求创建上下文

下面提供了示例上下文,将其保存为 context.ts 文件:

context.ts
context.ts
ts
import { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
export function createContext({ req, res }: CreateFastifyContextOptions) {
const user = { name: req.headers.username ?? 'anonymous' };
return { req, res, user };
}
export type Context = Awaited<ReturnType<typeof createContext>>;
context.ts
ts
import { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
export function createContext({ req, res }: CreateFastifyContextOptions) {
const user = { name: req.headers.username ?? 'anonymous' };
return { req, res, user };
}
export type Context = Awaited<ReturnType<typeof createContext>>;

创建 Fastify 服务器

tRPC 内置了 Fastify 适配器。该适配器可将 tRPC 路由器转换为 Fastify 插件。为避免大型批量请求出错,请确保按示例设置合适的 maxParamLength 选项。

技巧

由于 Fastify 插件系统和类型推断的限制,获取如 onError 等类型时可能存在困难。可添加 satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions'] 辅助 TypeScript 获得正确类型。

server.ts
ts
import {
fastifyTRPCPlugin,
FastifyTRPCPluginOptions,
} from '@trpc/server/adapters/fastify';
import fastify from 'fastify';
import { createContext } from './context';
import { appRouter, type AppRouter } from './router';
const server = fastify({
maxParamLength: 5000,
});
server.register(fastifyTRPCPlugin, {
prefix: '/trpc',
trpcOptions: {
router: appRouter,
createContext,
onError({ path, error }) {
// report to error monitoring
console.error(`Error in tRPC handler on path '${path}':`, error);
},
} satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions'],
});
(async () => {
try {
await server.listen({ port: 3000 });
} catch (err) {
server.log.error(err);
process.exit(1);
}
})();
server.ts
ts
import {
fastifyTRPCPlugin,
FastifyTRPCPluginOptions,
} from '@trpc/server/adapters/fastify';
import fastify from 'fastify';
import { createContext } from './context';
import { appRouter, type AppRouter } from './router';
const server = fastify({
maxParamLength: 5000,
});
server.register(fastifyTRPCPlugin, {
prefix: '/trpc',
trpcOptions: {
router: appRouter,
createContext,
onError({ path, error }) {
// report to error monitoring
console.error(`Error in tRPC handler on path '${path}':`, error);
},
} satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions'],
});
(async () => {
try {
await server.listen({ port: 3000 });
} catch (err) {
server.log.error(err);
process.exit(1);
}
})();

现在你的端点已可通过 HTTP 访问!

EndpointHTTP URI
getUserGET http://localhost:3000/trpc/getUserById?input=INPUT

where INPUT is a URI-encoded JSON string.
createUserPOST http://localhost:3000/trpc/createUser

with req.body of type User

如何启用订阅(WebSocket)

Fastify 适配器通过 @fastify/websocket 插件支持订阅。除上述步骤外,只需安装依赖项、在路由器中添加订阅、并在插件中启用 useWSS 选项即可。@fastify/websocket 要求最低 Fastify 版本为 3.11.0

安装依赖

bash
yarn add @fastify/websocket
bash
yarn add @fastify/websocket

导入并注册 @fastify/websocket

ts
import ws from '@fastify/websocket';
server.register(ws);
ts
import ws from '@fastify/websocket';
server.register(ws);

添加订阅

编辑之前步骤创建的 router.ts 文件,添加以下代码:

router.ts
ts
import { initTRPC } from '@trpc/server';
import { observable } from '@trpc/server/observable';
const t = initTRPC.create();
export const appRouter = t.router({
randomNumber: t.procedure.subscription(() => {
return observable<{ randomNumber: number }>((emit) => {
const timer = setInterval(() => {
emit.next({ randomNumber: Math.random() });
}, 1000);
return () => {
clearInterval(timer);
};
});
}),
});
router.ts
ts
import { initTRPC } from '@trpc/server';
import { observable } from '@trpc/server/observable';
const t = initTRPC.create();
export const appRouter = t.router({
randomNumber: t.procedure.subscription(() => {
return observable<{ randomNumber: number }>((emit) => {
const timer = setInterval(() => {
emit.next({ randomNumber: Math.random() });
}, 1000);
return () => {
clearInterval(timer);
};
});
}),
});

启用 useWSS 选项

server.ts
ts
server.register(fastifyTRPCPlugin, {
useWSS: true,
// ...
});
server.ts
ts
server.register(fastifyTRPCPlugin, {
useWSS: true,
// ...
});

现在您可以订阅 randomNumber 主题,每秒都会收到随机数 🚀。

Fastify 插件选项

nametypeoptionaldefaultdescription
prefixstringtrue"/trpc"
useWSSbooleantruefalse
trpcOptionsNodeHTTPHandlerOptionsfalsen/a