🦔

Next.jsのApp Router & RSCでApollo Clientを使う

2023/11/21に公開

はじめに

これまでRESTのバックエンド&インフラを主に担当していて、Next.jsもGraphQLも詳しくないのですが、GraphQLを学ぶついでに、最近よく聞くApp RouterとRSC(React Server Components)も学べたら一石二鳥じゃん!ということで触ってみたのでその記録を残します。

前提

GraphQLのバックエンドは構築済みとします。
私はGoのgqlgenというライブラリを使って構築しました。

リクエストとレスポンスは以下のような形式になっています(リクエストが左、レスポンスが右)。

今回のフロントのコードも含めて、ソースコードは以下に置いていますのでご参考までに!
https://github.com/hisami/graphql-go

また、Next.jsのプロジェクトの作成も完了していることとします。

やったこと

型定義のコード自動生成

必要なパッケージのインストール

GraphQLのスキーマ定義からフロント用のコードを生成するために、GraphQL Code Generatorを使います。

まずは必要なパッケージをインストールします。

npm i -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-graphql-request 
@graphql-codegen/typescript-operations @graphql-codegen/typescript-resolvers

設定ファイルの作成

graphql/codegen-client.yml
schema: ../backend/graph/schema.graphqls
documents: ./graphql/query/*.graphql
generates:
  ./graphql/dist/client.ts:
    plugins:
      - typescript
      - typescript-operations
      - typescript-graphql-request

スキーマ定義は、バックエンド構築時に構築したものを使いまわしています(schema:の部分)。
フロントエンドからのクエリを定義するファイルを以下のように記述します(documents:の部分)。

graphql/query/message.graphql
query getMessages {
  messages {
    id
    user
    text
    createdAt
  }
}

mutation postMessage($user: String!, $text: String!) {
  postMessage(user: $user, text: $text) {
    id
    user
    text
    createdAt
  }
}

コードの自動生成実行

これで準備ができたので、package.jsonにスクリプトを用意して、実行します。

package.json
  "scripts": {
    "gen": "graphql-codegen --config ./graphql/codegen-client.yml"
  }

うまくいけば、distディレクトリにclient.tsというファイルが生成されます。

Next.jsのApp Router & RSCでデータをフェッチする

ここからが本題です、Next.jsのRSCで使用する方法は、zennなどの日本語の記事はまだ少なかったのですが、以下のApolloの公式のブログを見ると、@apollo/experimental-nextjs-app-supportというライブラリを使えばできそうです。

https://www.apollographql.com/blog/announcement/frontend/using-apollo-client-with-next-js-13-releasing-an-official-library-to-support-the-app-router/

パッケージのインストール

npm i @apollo/client @apollo/experimental-nextjs-app-support

共通で使用する設定ファイルの作成

RSCでApollo Clientを使用するために、共通で使用する設定ファイルを作成します。

lib/client.ts
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";
import { registerApolloClient } from "@apollo/experimental-nextjs-app-support/rsc";

export const { getClient } = registerApolloClient(() => {
  return new ApolloClient({
    cache: new InMemoryCache(),
    link: new HttpLink({
      uri: "http://localhost:8080/query", // 各自の環境で書き換えてください
      fetchOptions: { cache: "no-store" }, // 一旦、キャッシュしない設定で逃げる
    }),
  });
});

page.tsxの編集

データを取得した結果をフロントに表示する部分です。

app/page.tsx
import { getClient } from "@/lib/apolloClient";
import { GetMessagesQuery, GetMessagesDocument } from "@/graphql/dist/client";

export default async function QueryPage() {
  // クエリ
  const { data: queryData } = await getClient().query<GetMessagesQuery>({
    query: GetMessagesDocument,
  });

  const messages = [...queryData.messages];
  return (
    <main>
      {messages
        .sort((a, b) => (a.createdAt > b.createdAt ? 1 : -1))
        .map((message) => (
          <div key={message.id}>
            <h1>{message.text}</h1>
          </div>
        ))}
    </main>
  );
}

表示結果

以下のように表示されればOKです!

まとめ

Next.jsもGraphQLもほとんど触ったことのない技術だったので、ざっと動くところまで通してみましたが、キャッシュとかまで考えると奥が深そうなので引き続きキャッチアップしていきたいと思います(一旦今回やキャッシュしない設定で逃げちゃいました)。

Discussion