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

概要

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

  • Next.js v13
  • tRPC v10
Usage with Next.js | tRPC
Next.js makes it easy for you to build your client and server together in one codebase. tRPC makes it easy to share types between them, ensuring typesafety for ...

以下のように 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>
  );
}

参考

Usage with Next.js | tRPC
Next.js makes it easy for you to build your client and server together in one codebase. tRPC makes it easy to share types between them, ensuring typesafety for ...
ふんわりざっくり大味で gRPC と tRPC の雰囲気を知る
tRPCを導入したら爆速でWebサービスをリリースできた話
FEELCAT 腹筋ローラー アブローラー スリムトレーナー アブホイール 上半身筋トレ 膝保護マット付き 耐荷重200kg
FEELCAT 腹筋ローラー アブローラー スリムトレーナー アブホイール 上半身筋トレ 膝保護マット付き 耐荷重200kg
JEAU CHAU 100% ヒハツパウダー 100g インド産 選別品 無添加 ロングペッパー
丁寧に選別した無添加のヒハツパウダーです。 スパイスは香りが命。加工方法も大事ですが、何より鮮度が重要です。 JEAU CHAU(ジョウショー)では、現地から新鮮なスパイスを調達し、素早くパッキング。 自信をもってオススメできる、素晴らしいスパイスです。 スパイスカレーだけでなく、様々なお料理でお楽しみください!
明治 チョコレート効果カカオ95%大袋 180g
・カカオの豊かな香りと強い苦味が特徴のカカオ分95%の高カカオチョコレートに大袋タイプが登場です。 ・標準36枚の個包装入りで、チョコレート効果を習慣的に食べる方や、健康を気にする家族や友人に配る際にもおすすめです。
ランドリン 柔軟剤 特大容量 クラシックフローラル 詰め替え 3倍サイズ 1440ml
ランドリンの香り人気No.1 *メーカー調べ 『着る香水』という発想で作られた柔軟剤。 うっとりするような優雅な気分をイメージした、上品でクラシカルな香りが持続します。 オーガニック抽出エキス配合で赤ちゃん用衣類にもご使用いただけます。 花粉吸着を抑制します。抗菌・防臭。 お得な詰め替え用3倍容量サイズ。 Amazon...
デルモンテ 食塩無添加 トマトジュース900g×12本
デルモンテが世界中から選抜したトマトをベストの配合でブレンド。とろりと濃厚で、完熟トマトの甘みと旨味が特長のトマトジュースです。 ・コップ1杯(200ml)でトマト4個分のリコピン ・コップ1杯(200ml)でGABA50mg ・食塩、砂糖不使用
YUBOEST ホットアイマスク USB 充電式 【コードレス】「純シルク製&極上リラックス」軽量 かわいい 持ち運び便利 タイマー設定 温度調節 繰り返し使用可能 家族 父の日 恋人 母 誕生日に プレゼント 日語説明書 ギフトケース包装 (ネイビー)
YUBOEST ホットアイマスク USB 充電式 アイマスク【コードレス】軽量 かわいい シルク 持ち運び便利 タイマー設定 温度調節 繰り返し使用可能 恋人 家族 父の日 恋人 母 誕生日に プレゼント 日語説明書 ギフトケース包装 (ネイビー)

コメント

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