📌

tRPC これから流行るかもしれないBFFフレームワークの紹介 |Offers Tech Blog

2022/10/20に公開


はじめに

こんにちは!!

プロダクト開発人材の副業転職プラットフォーム Offers を運営する株式会社 overflow 普通のバックエンドエンジニアの takkun7171 でございます。
最近 netflix で サイバーパンク エッジランナー を見て、やっぱりサイバーパンクいいなあと思って、PS5 のサイバーパンク 2077 を衝動買いしました w まああんなディストピアで幸せに生きていける気がしないけどね w

tRPCとは

こちらの記事で紹介されているのですが、
Theo 氏が提唱した最近話題の T3 Stac という技術スタックがあります。
https://zenn.dev/mikinovation/articles/20220911-t3-stack

この中の1つとして紹介されている tRPC が、
これから流行るかもしれない BFF フレームワークです。

何が良いの?

next.js の素の API よりも、TypeScript との親和性が高く、
型安全な API 開発が可能です。(VSCode で開発してると API の引数の型とか、間違ってると教えてくれます)

エンドポイントは1つで、ここにルーティングをゴニョゴニョ書いて行き、
引数や戻り値の型もこちらで設定し、クライアント側からはこの型をインポートするので
型安全な開発ができるということみたいです。

GraphQL よりも学習コストが低いようで、
自分のようにフロントエンド苦手勢にもサンプルを見たら割と直感的にサクッと動かせました。

今の所そこまで人口に膾炙していないのか、
より実践的に突っ込んで実装した日本語記事が少ないみたいです。
ですがコンセプトがシンプルで使いやすく、型安全な API 開発は一度体験すると戻れなさそうなので、これからジワジワと流行っていくんではないかと思っています。

基本的な使い方

公式サイトはこちらです
https://trpc.io/

next.js での使い方はこちらで、今回はこちらをやってみました
https://trpc.io/docs/v10/nextjs

最近更新したみたいで今までと書き方変わってますけど、
多少リファクタリングされただけみたいで基本的には同じです
https://github.com/trpc/trpc/commits/next/www/docs/nextjs/introduction.md

next.js は動いている前提です

まずは必要なものを取得

yarn add @trpc/server@next @trpc/client@next @trpc/react@next @trpc/next@next @tanstack/react-query

それで以下のファイルをコピるだけ!!

pages/api/trpc/[trpc].ts
import { initTRPC } from '@trpc/server';
import * as trpcNext from '@trpc/server/adapters/next';
import { z } from 'zod';

export const t = initTRPC.create();

// エンドポイントの設定
// inputが引数の型などの設定
// queryに処理内容書く。query内のinputはgetの値
// 更新系処理はqueryではなくmutationって書くみたい。その場合はpost
// https://trpc.io/docs/v10/server-side-calls#mutation-example
export const appRouter = t.router({
  hello: t.procedure
    .input(
      z.object({
        text: z.string().nullish(),
      })
      .nullish(),
    )
    .query(({ input }) => {
      return {
        greeting: `hello ${input?.text ?? 'world'}`,
      };
    }),
});

// export type definition of API
// こちらで型をexport。クライアント側でこいつを参照してくれるみたいで開発が捗る
export type AppRouter = typeof appRouter;

// export API handler
// Contextで認証後のuserの情報とか持たせることができるみたい
export default trpcNext.createNextApiHandler({
  router: appRouter,
  createContext: () => ({}),
});
utils/trpc.ts
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from '../pages/api/trpc/[trpc]';
// この一行がサンプルで抜けてた(2022/09/22時点)ので追加
import { httpBatchLink } from '@trpc/client';

function getBaseUrl() {
  if (typeof window !== 'undefined') // browser should use relative path
    return '';

  if (process.env.VERCEL_URL) // reference for vercel.com
    return `https://${process.env.VERCEL_URL}`;

  if (process.env.RENDER_INTERNAL_HOSTNAME) // reference for render.com
    return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;

  // assume localhost
  return `http://localhost:${process.env.PORT ?? 3000}`;
}

export const trpc = createTRPCNext<AppRouter>({
  config({ ctx }) {
    return {
      links: [
        httpBatchLink({
          /**
           * If you want to use SSR, you need to use the server's full URL
           * @link https://trpc.io/docs/ssr
           **/
          url: `${getBaseUrl()}/api/trpc`,
        }),
      ],
      /**
       * @link https://react-query-v3.tanstack.com/reference/QueryClient
       **/
      // queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },
    };
  },
  /**
   * @link https://trpc.io/docs/ssr
   **/
  ssr: true,
});
// => { useQuery: ..., useMutation: ...}
pages/_app.tsx
import type { AppType } from 'next/dist/shared/lib/utils';
import { trpc } from '../utils/trpc';
const MyApp: AppType = ({ Component, pageProps }) => {
  return <Component {...pageProps} />;
};
export default trpc.withTRPC(MyApp);
pages/index.tsx
import { trpc } from '../utils/trpc';
export default function IndexPage() {
  // これだけで使える。ちなみにmutation呼び出すときはuseMutation
  // textに型が当たってくれて捗る。helloも型推論されているみたい?
  const hello = trpc.hello.useQuery({ text: 'client' });
  if (!hello.data) {
    return <div>Loading...</div>;
  }
  return (
    <div>
      <p>{hello.data.greeting}</p>
    </div>
  );
}

それから

npm run dev


http://localhost:3000/
に hello client と表示されたら成功

特に解説もいらないくらいシンプルな感じですね
[trpc].ts に API のルーティングと処理を書いて、
trpc.xxxx.useQuery とかで呼び出すだけ。

まとめ

今回は tRPC について紹介してみました。
本当に初歩的な紹介だったのですが、さらに応用するには
こちらの prisma と組み合わせたリポジトリを参考にすると良いかと思います。
Context や Middlewares も実際に使うには必要になると思いますが、
こちらに関しても日本語の記事は少ないので、リポジトリ参考にするのが早そうです。
https://trpc.io/docs/v10/example-apps

関連記事

https://zenn.dev/offers/articles/20220425-universal-attitude
https://zenn.dev/offers/articles/20220523-component-design-best-practice
https://zenn.dev/offers/articles/20220415-leader-and-manager-roles-in-overflow

Offers Tech Blog

Discussion