Next.js v15にApolloを導入してGraphQLを試す!


 

こんにちは。Tomoyuki(@tomoyuki65)です。

気付けばNext.jsのv15がリリースされていましたが、フロントエンド開発の際にGraphQLを利用したいこともあると思います。

そんな私もGraphQLについては言葉だけ聞いたことがあるぐらいでよくわからないことが多かったので、Next.jsにApolloというGraphQLのライブラリを導入して試してみることにしました。

 



Next.js v15にApolloを導入してGraphQLを試す!

まずはNext.jsのプロジェクトを作成しますが、作成するには事前にnodeおよびnpmのインストールが必要になります。

それらの詳細は割愛させていただきますが、もしまだインストールしてない方は先にそちらの準備をお願いします。

ではまず以下のコマンドを実行し、Next.jsのプロジェクトを作成します。

$ npx create-next-app@latest graphql-sample

 

コマンド実行後、設定について聞かれるので以下のように選択(基本的にデフォルト設定)します。

 

プロジェクトの作成が完了後、以下のコマンドを実行してディレクトリを移動します。

$ cd graphql-sample

 

作成されたプロジェクトをテキストエディタで開き、以下のように各種ファイルが作成されていればOKです。

 

各種ライブラリのインストール

次に以下のコマンドを実行し、GraphQL用の各種ライブラリをインストールします。

$ npm i graphql @apollo/client @apollo/server
$ npm i --legacy-peer-deps @as-integrations/next @graphql-tools/utils @graphql-tools/merge
$ npm i -D --legacy-peer-deps @graphql-codegen/cli @graphql-codegen/client-preset @graphql-codegen/typescript @graphql-codegen/typescript-resolvers

※2行目と3行目のライブラリはNext.js15に対応していない?感じでオプション「–legacy-peer-deps」が必要になりました。

 

次に以下のコマンドを実行し、codegen用の設定ファイルを作成します。

$ touch codegen.ts

 

次に作成したファイルを次のように記述します。

import { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
    schema: "apollo/documents/**/*.gql",
    documents: ["apollo/documents/**/*.gql"],
    generates: {
        "./apollo/__generated__/client/": {
            preset: "client",
            plugins: [],
            presetConfig: {
                gqlTagName: "gql",
            },
        },
        "./apollo/__generated__/server/resolvers-types.ts": {
            plugins: ["typescript", "typescript-resolvers"],
        },
    },
    ignoreNoDocuments: true,
};

export default config;

 

次にcodegen実行用のコマンドを追加するため、package.jsonを以下のように修正します。

{

・・・
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "compile": "graphql-codegen",
    "watch": "graphql-codegen -w"
  },

・・・
}

 

GraphQLのスキーマ定義用のファイルを作成

次に以下のコマンドを実行し、GraphQLのスキーマ定義(GraphQL APIのデータ構造と型を定義するもの)用のファイルを作成します。

$ mkdir -p apollo/documents
$ cd apollo/documents
$ touch userSchema.gql
$ cd ../..

 

次に作成したファイルを以下のように記述します。

schema {
  query: Query
}

type Query {
  users: [User!]!
}

type User {
  id: Int
  name: String
}

query ALL_USERS {
  users {
    id,
    name
  }
}

 

次に以下のコマンドを実行し、スキーマ定義のファイルを作成します。成功すると「apollo/__generated__」配下に各種ファイルが作成されます。

$ npm run codegen

 

GraphQLのリゾルバー用のファイルを作成

次に以下のコマンドを実行し、リゾルバー(GraphQLサーバーがクライアントからのクエリを処理するために使用する関数)用のファイルを作成します。

$ mkdir -p apollo/resolvers
$ cd apollo/resolvers
$ touch user.ts index.ts
$ cd ../..

 

次に作成したファイルをそれぞれ以下のように記述します。

import { readFileSync } from "fs";
import { join } from "path";
import { IResolvers } from '@graphql-tools/utils'
import { Resolvers } from "../__generated__/server/resolvers-types";
import { User } from '../__generated__/client/graphql';

const userTypeDefs = readFileSync(
    join(process.cwd(), "apollo/documents/userSchema.gql"),
    "utf-8"
);

const userResolvers: IResolvers<Resolvers> = {
    Query: {
        users() {
            const USERS = []

            for (let i: number = 0; i < 3; i++) {
                const USER: User = {
                    id: i,
                    name: `User-${i+1}`
                }

                USERS.push(USER)
            }

            return USERS
        },
    },
};

export { userTypeDefs, userResolvers };

※実際にはこのリゾルバーの部分で外部APIからデータを取得し、スキーマ定義型に整形してreturnするようにします。

 

import { mergeResolvers } from '@graphql-tools/merge'
import { mergeTypeDefs } from '@graphql-tools/merge';
import { userTypeDefs, userResolvers } from './user'

const typeDefs = mergeTypeDefs([
    userTypeDefs,
]);

const resolvers = mergeResolvers([
    userResolvers,
]);

export {typeDefs, resolvers};

 

GraphQLサーバー用のファイルを作成

次に以下のコマンドを実行し、GraphQLサーバー用のファイルを作成します。

$ mkdir -p src/app/api/graphql
$ cd src/app/api/graphql
$ touch route.ts
$ cd ../../../..

 

次に作成したファイルを次のように記述します。

import { startServerAndCreateNextHandler } from "@as-integrations/next";
import { ApolloServer } from "@apollo/server";
import { Resolvers } from "../../../../apollo/__generated__/server/resolvers-types";
import { typeDefs, resolvers } from '../../../../apollo/resolvers/index';
import { NextRequest } from 'next/server';

const apolloServer = new ApolloServer<Resolvers>({ typeDefs, resolvers });

const handler = startServerAndCreateNextHandler<NextRequest>(apolloServer, {
    context: async req => ({ req }),
});

export { handler as GET, handler as POST };

 

GraphQLサーバーの起動

次に以下のコマンドを実行し、Next.jsのローカルサーバーを起動させ、GraphQLサーバーを使えるようにします。

$ npm run dev

 

次にブラウザで「http://localhost:3000」にアクセスし、以下のようにNext.js v15のページが表示されればOKです。

 

次にブラウザで「http://localhost:3000/api/graphql」にアクセスし、以下のようにGraphQLのUIページが表示されればOKです。

 

GraphQLを実行して試す

次にGraphQLを試してみますが、既にデフォルトでusersデータが取得するように設定されているため、画面右上の「▶︎Query」をクリックして実行します。

実行後、画面右側にユーザーのリゾルバーで定義した値が取得されて表示されればOKです。

 

例えばユーザーのname項目だけ取得したい場合は、Queryの記述を以下のように修正して実行してみて下さい。

実行後、以下のようにname項目だけ取得できればOKです。

 

このようにGraphQLを使うことによって取得項目を柔軟に変えることができるのが一つのメリットになります。

 



Next.jsのフロント画面の方からApolloのGraphQLを使えるようにする

次にNext.jsのフロントが画面からGraphQLでデータを取得し、それを画面に表示させてみます。

まずは以下のコマンドを実行し、GraphQL用のコンポーネントファイルを作成します。

$ cd apollo
$ touch client.ts
$ cd ..
$ mkdir -p src/components
$ cd src/components
$ touch ApolloClient.tsx User.tsx
$ cd ../..

 

次に作成したファイルをそれぞれ以下のように記述します。

import { ApolloClient, InMemoryCache } from "@apollo/client";

export const client = new ApolloClient({
    uri: "/api/graphql",
    cache: new InMemoryCache(),
});

 

"use client"

import { ApolloProvider } from "@apollo/client"
import { client } from "../../apollo/client"

export default function ApolloClient({ children }: React.PropsWithChildren) {
    return <ApolloProvider client={client}>{children}</ApolloProvider>
};

 

"use client"

import gql from 'graphql-tag'
import { useQuery } from "@apollo/client"

const USERS = gql(`
    query Query {
        users {
            id,
            name
        }
    }
`);

export default function User() {
    const { data, loading, error } = useQuery(USERS)
    if (loading) {
        return <div>読み込み中...</div>
    }

    return (
        <div>
            {error && <div>{error.message}</div>}
            <ul>
                { data &&
                  data.users.map((v: any, i: number) => (
                      <li key={String(i)}>
                          { `ID: ${v.id} 名前: ${v.name}` }
                      </li>
                  ))
                }
            </ul>
        </div>
    )
};

 

次に作成したApolloClientコンポーネントをトップのlayout.tsxに追加します。

import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";
import ApolloClient from "../components/ApolloClient";

const geistSans = localFont({
  src: "./fonts/GeistVF.woff",
  variable: "--font-geist-sans",
  weight: "100 900",
});
const geistMono = localFont({
  src: "./fonts/GeistMonoVF.woff",
  variable: "--font-geist-mono",
  weight: "100 900",
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        <ApolloClient>
          {children}
        </ApolloClient>
      </body>
    </html>
  );
}

 

Next.jsにユーザー情報を表示させるページを追加

次に以下のコマンドを実行し、ユーザー情報を表示させるページのファイルを作成します。

$ mkdir -p src/app/users
$ cd src/app/users
$ touch page.tsx
$ cd ../../..

 

次に作成したファイルを以下のように記述します。

import User from "../../components/User"

export default function Users() {
    return (
        <User />
    );
}

 

次にNext.jsのサーバーを起動後、ブラウザで「http://localhost:3000/users」にアクセスし、以下のようにGraphQLからユーザー情報を取得して表示されればOKです。

 



最後に

今回はNext.jsのv15でApolloのGraphQLを試す方法についてご紹介しました。

おそらく中規模以上のフロントエンド開発をする際などはGraphQLを使った方がよいこともあると思う(逆に小規模開発では学習コストが高い)ので、基本的な部分は知っておくとよさそうです。

これからGraphQLを試したい方は、ぜひ参考にしてみて下さい。

 

The following two tabs change content below.

Tomoyuki

SEを5年経験後、全くの未経験ながら思い切ってブロガーに転身し、月間13万PVを達成。その後コロナの影響も受け、以前から興味があったWeb系エンジニアへのキャリアチェンジを決意。現在はWeb系エンジニアとして働きながら、プロゲーマーとしても活躍できるように活動中。








シェアはこちらから


【2024年】おすすめのゲーミングPC

モンハンワイルズの発売日とPC版(Steam版)の推薦スペックが公開されたので、おすすめのゲーミングPCをご紹介!


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です