Next.js + tRPC のチュートリアルをやってみる

概要

tRPC 公式の Next.js サンプルを読み解いていく。

  • Next.js v13
  • tRPC v10
Set up with Next.js Pages Router | tRPC
This guide is for Next.js Pages Router. If you are using Next.js App Router with React Server components, check out the ...

以下のように hello client と表示されるだけのシンプルなアプリ。

tRPCざっくり

公式ドキュメントより全体像。src ディレクトリにまとめられているがどっちでも大丈夫。

.
├── prisma  # <-- if prisma is added
│   └── [..]
├── src
│   ├── pages
│   │   ├── _app.tsx  # <-- add `withTRPC()`-HOC here
│   │   ├── api
│   │   │   └── trpc
│   │   │       └── [trpc].ts  # <-- tRPC HTTP handler
│   │   └── [..]
│   ├── server
│   │   ├── routers
│   │   │   ├── _app.ts  # <-- main app router
│   │   │   ├── post.ts  # <-- sub routers
│   │   │   └── [..]
│   │   ├── context.ts   # <-- create app context
│   │   └── trpc.ts      # <-- procedure helpers
│   └── utils
│       └── trpc.ts  # <-- your typesafe tRPC hooks
└── [..]

サンプルで追加するファイル。

  • src/pages/_app.tsx : withTRPC() HOC を置くところ
  • src/pages/api/trpc/[trpc].ts : エンドポイントAPI(実態は routers 配下に実装)
  • src/server/routers/_app.ts : エンドポイントの実装
  • src/server/routers/posts.ts : 他のエンドポイントも routers 配下にに追加(サンプルでは未実装)
  • src/server/context.ts : プロシージャヘルパー(サンプルでは未実装)
  • src/server/trpc.ts : server 側 trpc 設定
  • src/utils/trpc.ts : client 側の trpc 設定

実装

tRPCエンドポイント作成 (Create a tRPC router)

server 側でエンドポイント API を作成していく。

はじめに initTRPC() を tRPC バックエンドを初期化する。

server/trpc.ts
import { TRPCError, initTRPC } from "@trpc/server";

// Avoid exporting the entire t-object
// since it's not very descriptive.
// For instance, the use of a t variable
// is common in i18n libraries.
const t = initTRPC.create();

// Base router and procedure helpers
export const router = t.router;
export const procedure = t.procedure;

「hello world」を返す API (router) を作成する。
Next.js の API Routes は通常 pages/api/ 配下に作成していくが、tRPC ルータは server/routers/ 配下に作成していく。

server/routers/_app.ts
import { z } from 'zod';
import { procedure, router } from '../trpc';
export const appRouter = router({
  hello: procedure
    .input(
      z.object({
        text: z.string(),
      }),
    )
    .query(({ input }) => {
      return {
        greeting: `hello ${input.text}`,
      };
    }),
});
// export type definition of API
export type AppRouter = typeof appRouter;

Next.js API Routes には tRPC ルータに委任するための設定ファイルを定義しておく。

pages/api/trpc/[trpc].ts
import * as trpcNext from '@trpc/server/adapters/next';
import { appRouter } from '../../../server/routers/_app';
// export API handler
export default trpcNext.createNextApiHandler({
  router: appRouter,
  createContext: () => ({}),
});

サーバ側はこれで完了。

tRPC クライアント作成 (Create tRPC hooks)

tRPCエンドポイントを呼び出すためのクライアントを設定する。

utils/trpc.ts
import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from '../server/routers/_app';

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://tanstack.com/query/v4/docs/reference/QueryClient
       **/
      // queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },
    };
  },
  /**
   * @link https://trpc.io/docs/ssr
   **/
  ssr: false,
});

クライアント側はこれで完了。

_app.tsx に HOC 設定 (Configure _app.tsx)

withTRPC() でクライアント側アプリ(MyApp)を包むことで Next.js 全体(クライアント側・サーバ側両方)で trpc を呼び出せるように設定。

pages/_app.tsx
import type { AppType } from 'next/app';
import { trpc } from '../utils/trpc';
const MyApp: AppType = ({ Component, pageProps }) => {
  return <Component {...pageProps} />;
};
export default trpc.withTRPC(MyApp);

API を呼び出す (Make an API request)

Next.js のページから作成した tRPC エンドポイントを tRPC クライアント経由で呼び出す。

ここで使っている useQuery は react-query のもの。

pages/index.tsx
import { trpc } from '../utils/trpc';

export default function IndexPage() {
  const hello = trpc.hello.useQuery({ text: 'client' });
  if (!hello.data) {
    return <div>Loading...</div>;
  }
  return (
    <div>
      <p>{hello.data.greeting}</p>
    </div>
  );
}

参考

Set up with Next.js Pages Router | tRPC
This guide is for Next.js Pages Router. If you are using Next.js App Router with React Server components, check out the ...
ふんわりざっくり大味で gRPC と tRPC の雰囲気を知る
tRPCを導入したら爆速でWebサービスをリリースできた話
https://amzn.to/3Vuk9hA
https://amzn.to/3WtZrzG
Amazon | 明治 チョコレート効果カカオ95%大袋 180g | チョコレート効果 | 板チョコ・チョコバー 通販
明治 チョコレート効果カカオ95%大袋 180gが板チョコ・チョコバーストアでいつでもお買い得。当日お急ぎ便対象商品は、当日お届け可能です。アマゾン配送商品は、通常配送無料(一部除く)。
Amazon.co.jp: ランドリン 柔軟剤 特大容量 クラシックフローラル 詰め替え 3倍サイズ 1440ml : ドラッグストア
Amazon.co.jp: ランドリン 柔軟剤 特大容量 クラシックフローラル 詰め替え 3倍サイズ 1440ml : ドラッグストア
Amazon.co.jp: 【Amazon.co.jp限定】デルモンテ 食塩無添加トマトジュース900g×12 : 食品・飲料・お酒
Amazon.co.jp: 【Amazon.co.jp限定】デルモンテ 食塩無添加トマトジュース900g×12 : 食品・飲料・お酒
https://amzn.to/3ZfWW5N

コメント

タイトルとURLをコピーしました