概要
近年、API の開発において 型安全性 や 開発効率の向上 が求められる中で、tRPC は非常に魅力的な選択肢となっています。しかし、tRPC を導入しているプロジェクトはまだ少なく、その利便性が十分に伝わっていないのが現状です。
この記事では、tRPC の魅力と活用方法 を詳しく解説し、導入を検討している方に向けてメリットをお伝えします。
この記事でわかること
- RPC とは何か
-
tRPC の特徴とメリット
- 型安全性による開発効率の向上
- API の状態管理の簡素化
- バリデーションチェックの容易さ
- T3 Stack の紹介
tRPC を活用することで、フロントエンドとバックエンドの型を統一し、よりスムーズな開発を実現できます。ぜひこの記事を参考に、tRPC の魅力を体感してください!
そもそも RPC とは
RPC(Remote Procedure Call)は、遠隔にあるコンピュータの関数を呼び出す技術 です。簡単に言うと、ネットワークを介して別のコンピュータ上にある関数を、あたかもローカルにある関数のように呼び出すことができます。
RPC の特徴
-
ローカル関数呼び出しと同じ感覚: 開発者はネットワーク通信の複雑さを意識せず、関数を呼び出すだけでリモートの処理を実行できます
-
分散システムの構築に適している: 複数のサーバー間で関数を呼び出し合うことで、大規模なシステムを構築しやすくなります
通常の関数呼び出し
通常の関数呼び出しは、自身のプログラム内で関数を実行し、結果を受け取ります。
RPC の関数呼び出し
通常の関数と異なりネットワークを介して別のコンピュータで関数を実行。
tRPC とは
tRPC は、TypeScript を使った RPC フレームワーク です。クライアントとサーバー間の通信を型安全かつ簡単に行えるよう設計されています。特に、フロントエンドとバックエンド間で型安全な API 呼び出しを実現するために作られました。
tRPC は、従来の REST API とは異なり、型定義を自動的に共有することで、クライアントとサーバ間の型不一致を防ぎます。これにより、API の変更に伴うエラーを未然に防ぎ、開発者がより安全にコードを書くことができます。
サーバー側
以下はtRPCでサーバー側にプロシージャを定義する例です。このコードではZodを使って入力と出力の型を定義しています。
export const postRouter = createTRPCRouter({
hello: publicProcedure
.input(z.object({ text: z.string() }))
.query(({ input }) => {
return {
greeting: `Hello ${input.text}`,
};
}),
});
クライアント側
クライアントでは、サーバー側で定義したプロシージャをTanStack Query 経由で呼び出します。
const { data } = api.post.hello.useQuery({ text: "world" });
このように、クライアントとサーバー間で型が共有されているため、API呼び出し時のエラーが未然に防止されます。
tRPC の実際に使ってみて良かった点
tRPC を実際に使ってみて、めちゃくちゃ良かったなと思った点を挙げてみました!これから tRPC を検討する方の参考になれば嬉しいです 🙌
1. 型安全に API の実装ができる🛡️
tRPC の最大の魅力は、型安全性です。TypeScript の型システムをフル活用できるので、クライアントとサーバー間の通信で型の不一致によるエラーがほぼなくなります。
Zodとの連携が非常に効果的: tRPC は Zod をサポートしており、API の入力(input)と出力(output)に対してバリデーションを簡単に定義できます。
hello: publicProcedure
.input(z.object({ text: z.string() }))
.output(z.object({ greeting: z.string() }))
.query(({ input }) => {
return {
greeting: `Hello ${input.text}`,
};
}),
-
入力バリデーション:
input
でリクエストの型を定義し、不正なデータを防ぐ - 出力バリデーション: output でレスポンスの型を定義し、クライアントに返すデータの整合性を保証
2. API の状態管理が簡単 🚀
tRPC を使えば、API の状態管理が非常にシンプルになります。特に TanStack Query が組み込まれているため、データフェッチングやキャッシュ管理がスムーズに行えます。
- 従来は Server Component / Client Component それぞれで API クライアントを考える必要がありましたが、tRPC は TanStack Query と統合されているため、特に意識せずに実装可能です
Server Component でのデータ取得
// prefetch など
const data = await api.post.hello({ text: "world" });
Client Component でのデータ取得
// usePrefetchQuery, useSuspenseQuery など
const { data } = api.post.hello.useQuery({ text: "world" });
3. 柔軟なプロシージャ定義(Middleware の導入)🏗️
tRPC では、関数ごとに呼び出しルールを定義することが可能です。
API ごとに middleware を設定できるイメージで、これを活用すると認証済みユーザーのみが実行可能な API などを簡単に実装できます。
公開 API(認証不要)
export const publicProcedure = t.procedure;
認証が必要な API
export const protectedProcedure = t.procedure
.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
});
4. デバッグがしやすい 🛠️
tRPC には、開発をスムーズにするためのデバッグ機能が備わっています。
以下のように関数の引数・返り値・処理時間を可視化できるため、API の動作を直感的に把握できます。
これにより、API の呼び出しがどのように行われたのかを簡単に確認でき、デバッグの効率が向上します。
まとめ
tRPC を活用することで、以下のようなメリットを実感できます。
✅ 型安全な API 実装が可能(型の不一致によるバグを未然に防ぐ)
✅ API の状態管理が簡単(TanStack Query との統合)
✅ バリデーションチェックが容易(Zod を活用)
✅ デバッグがしやすい(API の処理を可視化)
フロントエンドとバックエンドの両方が TypeScript なら、tRPC を使わない理由は、ほとんどないのではないかと思います。あとは、Next.js の API Routes を BFF(Backend for Frontend)として活用する場合なども、tRPC は非常に有効です。
ぜひ一度触ってみてください! 🎉
tRPC を触ってみたい方には、T3 Stack がおすすめです。