メインコンテンツへスキップ
バージョン: 10.x

プロシージャの定義

非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

プロシージャはクライアントに公開される関数であり、以下のいずれかの種類があります:

  • Query - データ取得に使用され、通常はデータを変更しません

  • Mutation - データ送信に使用され、作成・更新・削除目的で頻繁に利用されます

  • Subscription - これは不要な場合もあり、専用ドキュメントも用意されています

tRPCにおけるプロシージャは、バックエンド関数を作成するための非常に柔軟なプリミティブです。イミュータブルなビルダーパターンを採用しているため、再利用可能なベースプロシージャを作成して複数のプロシージャ間で機能を共有できます。

プロシージャの作成

tRPCセットアップ時に作成するtオブジェクトは初期t.procedureを返し、これが他のすべてのプロシージャの基盤となります:

ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
 
const t = initTRPC.context<{ signGuestBook: () => Promise<void> }>().create();
 
export const router = t.router;
export const publicProcedure = t.procedure;
 
const appRouter = router({
// Queries are the best place to fetch data
hello: publicProcedure.query(() => {
return {
message: 'hello world',
};
}),
 
// Mutations are the best place to do things like updating a database
goodbye: publicProcedure.mutation(async (opts) => {
await opts.ctx.signGuestBook();
 
return {
message: 'goodbye!',
};
}),
});
ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
 
const t = initTRPC.context<{ signGuestBook: () => Promise<void> }>().create();
 
export const router = t.router;
export const publicProcedure = t.procedure;
 
const appRouter = router({
// Queries are the best place to fetch data
hello: publicProcedure.query(() => {
return {
message: 'hello world',
};
}),
 
// Mutations are the best place to do things like updating a database
goodbye: publicProcedure.mutation(async (opts) => {
await opts.ctx.signGuestBook();
 
return {
message: 'goodbye!',
};
}),
});

再利用可能な「ベースプロシージャ」

一般的なパターンとして、t.procedurepublicProcedureとしてリネーム・エクスポートすることを推奨します。これにより、特定ユースケース向けに他の名前付きプロシージャを作成・エクスポートする余地が生まれます。この「ベースプロシージャ」パターンはtRPCにおけるコードと動作の再利用の中核であり、ほぼすべてのアプリケーションで必要となるでしょう。

以下の例はユーザー入力を受け取り、門番のようにそれを認可します。これは明らかに単純化のための作為的な例であり、アプリケーションユーザーを安全に認可する適切な方法ではありません。実際には、ヘッダーコンテキストミドルウェアメタデータを組み合わせて、ユーザーの認証と認可を行うことをお勧めします。

ts
export const authorizedProcedure = publicProcedure
.input(z.object({ townName: z.string() }))
.use((opts) => {
if (opts.input.townName !== 'Pucklechurch') {
throw new TRPCError({
code: 'FORBIDDEN',
message: "We don't take kindly to out-of-town folk",
});
}
 
return opts.next();
});
 
export const appRouter = t.router({
hello: authorizedProcedure.query(() => {
return {
message: 'hello world',
};
}),
goodbye: authorizedProcedure.mutation(async (opts) => {
await opts.ctx.signGuestBook();
 
return {
message: 'goodbye!',
};
}),
});
ts
export const authorizedProcedure = publicProcedure
.input(z.object({ townName: z.string() }))
.use((opts) => {
if (opts.input.townName !== 'Pucklechurch') {
throw new TRPCError({
code: 'FORBIDDEN',
message: "We don't take kindly to out-of-town folk",
});
}
 
return opts.next();
});
 
export const appRouter = t.router({
hello: authorizedProcedure.query(() => {
return {
message: 'hello world',
};
}),
goodbye: authorizedProcedure.mutation(async (opts) => {
await opts.ctx.signGuestBook();
 
return {
message: 'goodbye!',
};
}),
});