Fastify アダプター
サンプルアプリケーション
Fastify アダプターを使い始めるのに最適な方法は、サンプルアプリケーションを確認することです。
説明 | リンク |
---|---|
|
Fastify で tRPC を使用する方法
依存関係のインストール
bash
yarn add @trpc/server fastify zod
bash
yarn add @trpc/server fastify zod
Zod は必須の依存関係ではありませんが、以下のサンプルルーターで使用されています。
ルーターの作成
まず最初に、クエリ、ミューテーション、およびサブスクリプションを処理するためのルーターが必要です。
サンプルルーターを以下に示します。router.ts
という名前のファイルに保存してください。
router.ts
router.tsts
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 APIexport type AppRouter = typeof appRouter;
router.tsts
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 APIexport type AppRouter = typeof appRouter;
ルーターファイルが大きくなりすぎたら、ルーターを複数のサブルーターに分割し、それぞれを独自のファイルに実装してください。次に、それらをマージして、単一のルート appRouter
にします。
コンテキストの作成
次に、各リクエストに対して作成されるコンテキストが必要です。
サンプルコンテキストを以下に示します。context.ts
という名前のファイルに保存してください。
context.ts
context.tsts
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.tsts
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 オプションを適切な値に設定してください。
Fastify のプラグインシステムと型の推論には制限があるため、たとえば onError
の型を正しく取得する際に問題が発生する可能性があります。TypeScript を支援し、正しい型を取得するために、satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions']
を追加できます。
server.tsts
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 monitoringconsole.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.tsts
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 monitoringconsole.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 経由で利用可能になりました!
エンドポイント | HTTP URI |
---|---|
getUser | GET http://localhost:3000/trpc/getUserById?input=INPUT INPUT は URI エンコードされた JSON 文字列です。 |
createUser | POST http://localhost:3000/trpc/createUser req.body の型は 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.tsts
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.tsts
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.tsts
server.register(fastifyTRPCPlugin, {useWSS: true,// ...});
server.tsts
server.register(fastifyTRPCPlugin, {useWSS: true,// ...});
大丈夫です。トピック randomNumber
をサブスクライブすると、1 秒ごとに乱数が届くはずです🚀。
Fastify プラグインオプション
名前 | 型 | オプション | デフォルト | 説明 |
---|---|---|---|---|
prefix | string | true | "/trpc" | |
useWSS | boolean | true | false | |
trpcOptions | NodeHTTPHandlerOptions | false | n/a |