wheatandcatの開発ブログ

React Nativeで開発しているペペロミア & memoirの技術系記事を投稿してます

tRPCを試してみた

最近、話題のtRPCを試してみたので記事にしました。

tRPCとは?

trpc.io

  • スキーマやコード生成なしで型安全なAPIの連携が行えるPRCフレームワーク
  • TypeScriptに特化しており、非常にシンプルに実装できる
  • 比較対象としては、GraphQLOpenAPIなどの技術に該当するが、tRPCはBFFで使われることが前提にありそうなので単純な比較は出来なさそう

そもそもRPCとは?

  • RPC ( Remote Procedure Call ) とは、ネットワークで繋がっている別のコンピュータのプログラムを実行できるようにする技術
  • クライアント側からサーバー側への疎通を行う際に、具体的な通信手段やプロトコルを意識することなく、関数の呼び出しを行うことがでやり取りが行える仕組み
  • Googleが開発したRPCのプロトコルなので、gRPCという命名になっている
  • tRPCのtはTypeScriptを表して

学ぶモチベーション

  • BFF構成で多数のマイクロサービスにアクセスするようなプロダクトの場合、BFF部分はfrontendエンジニアが管理することが多い
  • その場合の選択肢としてtRPCを使うのが有効なのではないかなと考え検証
  • frontend側でAPI周りを型安全にするには、OpenAPIGraphQLを使うことが多かったが、frontendエンジニアが扱うには難易度が高い & コードジェネレートが必要なパターンが多い
  • tRPCなら、コードジェネレートも不要で、frontendエンジニアでも使い慣れたTypeScriptで書けて便利そう

リポジトリ

今回で検証したコードは以下で確認できる

github.com

github.com

実装

Quickstart

trpc.io

公式のQuickstartを元に簡単なサーバー側の実装をしてみる。

import { createHTTPServer } from "@trpc/server/adapters/standalone";
import { initTRPC } from "@trpc/server"

const t = initTRPC.create();

const appRouter = t.router({
  helloWorld: t.procedure.query(() => {
    return "Hello World";
  }),
});

export type AppRouter = typeof appRouter;

const server = createHTTPServer({
  router: appRouter,
});

server.listen(8000);

上記をtRPCを呼ぶスクリプトの実装が以下の通り

import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
import type { AppRouter } from "./server";

const trpc = createTRPCProxyClient<AppRouter>({
  links: [
    httpBatchLink({
      url: "http://localhost:3000",
    }),
  ],
});

trpc.helloWorld.query().then((res) => {
  // output "Hello World"
  console.log(res);
});

こんな感じでメソッドを呼ぶだけでAPI通信が行える。

以下みたいな感じでコードの補完もされる。

ReactでtRPCを呼ぶ

trpc.io

公式でHooksが提供されているので、こちらを使用して実装。

最初にProvider部分を実装。

containers/Trpc.tsx

import { useState } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { httpBatchLink } from "@trpc/client";
import { trpc } from "../utils/trpc";

type Props = {
  children: React.ReactNode;
};

function Trpc(props: Props) {
  const [queryClient] = useState(() => new QueryClient());
  const [trpcClient] = useState(() =>
    trpc.createClient({
      links: [
        httpBatchLink({
          url: "http://localhost:8080",
        }),
      ],
    })
  );

  return (
    <trpc.Provider client={trpcClient} queryClient={queryClient}>
      <QueryClientProvider client={queryClient}>
        {props.children}
      </QueryClientProvider>
    </trpc.Provider>
  );
}

export default Trpc;

上記のProviderを作成すれば、以下のコードのようにメソッドを呼んでReactでも簡単にAPIの通信が実行できる。

Page.tsx

import { trpc } from "./utils/trpc";

export default function IndexPage() {
  const userQuery = trpc.helloWorld.useQuery();

  return <div>{userQuery.data}</div>;
}

React + tRPC + Prismaでデモを実装

github.com

BFFとは、少し話がズレましたが開発の体験が結構良かった

Deno + tRPCを試す

github.com

  • 上記のリポジトリで実装
  • モチベーション
    • TypeScriptをデプロイするのが面倒だったので、Denoで行けたら1つで全て済むと思い検証
  • 結果
    • tRPCの実装はできるけど、Denoで実装したファイルをimportできるのはDenoのみなので、結果フロントエンドもDenoで実装する必要がある
    • こうなってくると旨味が薄れるので、まだ実用段階では無さそうという結果になった

まとめ

  • コードジェネートして型安全をする方法に慣れきっていたが、tRPCはコードジェネートしなくても型安全が実現できるので手軽
  • TypeScript周りのツールも大分充実してきて書きやすいので、tRPCを使っていくのも全然有り
  • BFFでの使用は、かなり有り。
  • 手軽にtRPCを試したい場合は、以下のT3 Appを使用するのが良いと思うので、興味のある方は試してみたら良いと思います

create.t3.gg