【Next.js】ApolloClient×GraphQLCodegen 使ってみた


## はじめに
ApolloClient×GraphqlCodegenの組み合わせががとても書いやすく感動したので、軽く使い方をまとめておきます。
今回はユーザーの登録と取得を例にファイルの生成からAPIを叩くまでの流れを軽く紹介していこうと思います。
 間違いがあれば指摘していただけると嬉しいです。
 
## 今回使用したライブラリ
```
@apollo/client
@graphql-codegen/cli
@graphql-codegen/typescript
@graphql-codegen/typescript-operations
@graphql-codegen/typescript-react-apollo
@graphql-codegen/client-preset
@graphql-codegen/introspection
```
## codegen.yml

生成されるファイルの種類やオプションを定義します。
この設定により,、型定義やHooksが自動生成されます。

```yml
overwrite: true
schema: "schema.graphql"
documents: "src/**/*.gql"
generates:
  src/generated/graphql.ts:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-apollo"
    config:
      withHooks: true 
      withComponent: false
      withHOC: false
```

overwrite:
    既存のファイルを上書きするかどうか。

schema:
    スキーマファイルのパス。

documents:
    ドキュメント（クエリ、ミューテーション等）のパス。

generates:
    生成されたファイエルの配置場所

plugins:
    各種プラグイン 個別インストールが必要

config:
    withHooks: 
            Apollo Client用のカスタムフックの自動生成有効
    withComponent: withHOC: false 
            Reactコンポーネントと高階コンポーネントの自動生成無効

## package.json
自動生成のコマンドを定義します
```json-doc
scripts{
    "codegen": "graphql-codegen --config codegen.yml"
}
```
## schema.gql
使用するデータ型やAPIのクエリ、ミューテーションを定義します。
```js
scalar Upload
type User {
  userId: ID!
  email: String!
  name: String!
}

type Query {
  user(userId: ID!): User
}

type Mutation {
  createUser(name: String!): User
}
```


# document

GraphQLのドキュメントは、アプリケーションが実際にGraphQLサーバーに送信する操作を定義します。以下の例では、ユーザーを取得し、新しいユーザーを作成する操作を定義しています。

```js
//User.gql

query GetUser($userId: ID!) {
  user(userId: $userId) {
    userId
    email
    name
  }
}

mutation CreateUser($name: String!) {
  createUser(name: $name) {
    userId
    email
    name
  }
}
```


# 生成コマンド
このコマンドを実行することで、codegen.ymlに定義された設定に基づいて、ファイルが自動生成されます。
```
 npx graphql-codegen    
 ```


# apolloの準備
HTTPリンクと認証リンク、Apollo Clientインスタンスを作成します。
```tsx
import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";

const httpLink = createHttpLink({
  uri: "http://hogehoge"
});

const authLink = setContext((_, { headers }) => {
  const token = localStorage.getItem("token");
  return {
    headers: {
      ...headers,
      authorization: token 
    },
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});



import type { AppProps } from "next/app";
import { ApolloProvider } from "@apollo/client";
import client from "@/lib/apollo/client";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ApolloProvider client={client}>
      <AuthProvider>
        <Component {...pageProps} />
      </AuthProvider>
    </ApolloProvider>
  );
}

```

## Query叩いてみる
ApolloClientのuseQueryフックを使用して、サーバーからデータを取得します。
```tsx
import { useQuery } from "@apollo/client";
import {
  GetUserDocument, 
  GetUserQuery,          
  GetUserQueryVariables, 
} from "@/generated/graphql";


export const useGetUser = (userId: string) => {
  const { data, loading, error } = useQuery<
    GetUserQuery,
    GetUserQueryVariables
  >(GetUserDocument, {
    variables: { userId: userId },
  });
  return { data, loading, error };
};


export default function Home() {
  const { data, loading, error } = useGetUser(userId!);
  if (loading) return <div>loading...</div>;
  if (error) return <div>error</div>;
  return (
      <div>{data.name}</div>
  );
}
```

# mutation叩いてみる
ApolloClientのuseMutationフックを使用して、サーバーにデータを変更するリクエストを送信します。
```tsx
import { useMutation } from "@apollo/client";
import {
  CreateUserMutation,
  CreateUserMutationVariables,
  CreateUserDocument,
} from "@/generated/graphql";

export const useCreateUser = () => {
  const [createUser, { data, loading, error }] = useMutation<
    CreateUserMutation,
    CreateUserMutationVariables
  >(CreateUserDocument);
  return { createUser, data, loading, error };
};


export const CreateUser = () => {
  const { createUser, data } = useCreateUser();
  
  const handleCreate = async () => {
    try {
        await createUser({
          variables: { name: userName }
        });
        console.log("ユーザー登録完了");
      }
      return data
    } catch (err) {
      console.log(err);
    }
  };

```
# 参考文献
https://www.apollographql.com/docs/react/

https://the-guild.dev/graphql/codegen/docs/guides/react-vue

https://qiita.com/mizchi/items/fb9f598cea94d2c8072d

https://qiita.com/seya/items/26c8a0dc549a10efcdf8