【Next.js/Hasura】GraphQL環境を10分で構築

## はじめに
　最近謎にGraphQLが人気を集めている。
　以前インターン先で[Hasura](https://hasura.io/)を利用する機会があったため爆速でGraphQL環境を構築する。
　最終的にプロダクトにはNest.jsが採用されHasuraは使ってないが、一通り触った所感個人開発を行うのにこれほど便利なものはないだろう。

## 環境構築

### Hasuraの取得
　早速[Hasura公式](https://hasura.io/docs/latest/getting-started/docker-simple/)から`docker-compose.yml`ファイルをダウンロードする。下記コマンドは`wget`での例であり、`curl`にも対応している。
``` bash
wget https://raw.githubusercontent.com/hasura/graphql-engine/stable/install-manifests/docker-compose/docker-compose.yaml
```

　ダウンロードされたファイルから`HASURA_GRAPHQL_ADMIN_SECRET`をコメントインし、任意の値に書き換える。この値がフロントエンドと通信する際のSecretTokenとなる。
```diff:docker-compose.yml
- ## HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
+ HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
```

### Next.js appの作成
　先程ダウンロードしたファイルにnext.jsのための情報を追記する。下記サービスをservices項目に追加する。nodeバージョンとportは任意の値に書き換える。サンプルではnodeバージョン`18`、portは`3000`となっている。
```yaml:docker-compose.yml
web:
    image: node:18
    restart: always
    volumes:
      - .:/opt/web
    working_dir: /opt/web
    ports:
      - "3000:3000"
    tty: true
```

　サービスの追加ができたら下記コマンドでコンテナ郡を立ち上げる。
```bash
docker-compose up
# docker-compose up -d   //バックグラウンドでの実行
```
　コンテナが立ち上がったら`web`コンテナに入りnext.js appを作成する。app作成時の設定はデフォルトでも問題ない。作成するサービスにあわせて随時変更することを推奨。
```bash
docker-compose exec web bash
npx create-next-app@latest
```

　next.js appの作成が終わったら、コンテナ内でプロジェクトファイルを移動する。docker-compose.ymlファイルが存在るディレクトリとプロジェクトディレクトリを同じ階層にするために行う。プロジェクトディレクトリを移行しない場合はdocker-compose.ymlファイル内webサービスの`volumes`を書き換える必要がある。
```bash
mv $app_name .
rm -r $app_name
```

　現在作成されたファイルはすべてroot権限となっているため、プロジェクトディレクトリ以下のファイル権限を変更する。プロジェクトディレクトリがある階層に移動し、下記コマンドで権限を変更する。権限を変更しないとファイル変更時に毎回パスワードを聞かれ面倒。
```bash
sudo chmod 755 -R app_name
sudo chown $USER:$USER -R app_name
```

　最後に、docker-compose.ymlにコマンドを設定し、コンテナ起動時にnext.js serverが立ち上がるよう変更を加える。先程追加したwebサービスを一部書き換える。
```diff:docker-compose.yml
- tty: true
+ command: npm run start
```

### Next.jsからHasuraに接続
　`Appolo Client`を用いてNext.jsからHasuraに接続する。webコンテナ内から下記コマンドを用いてgraphqlとapollo clientをインストールする。

```bash
npm i @apollo/client graphql
```

インストールが終わったら、Hasuraに接続するための情報を`.env`ファイルにまとめる。`NEXT_PUBLIC_HASURA_ADMIN_SECRET`の値はdocker-compose.ymlファイルで記載した値を記入する。
```.env
NEXT_PUBLIC_GRAPHQL_ENDPOINT = http://localhost:8080/v1/graphql
NEXT_PUBLIC_HASURA_ADMIN_SECRET = myadminsecretkey
```

　実際にHasuraに接続するため、apollo clientのproviderを設定する。headersに`x-hasura-admin-secret`を設定する。
```typescript:_app.tsx
import "@/styles/globals.css";
import {
  ApolloClient,
  ApolloProvider,
  InMemoryCache,
  createHttpLink,
} from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import type { AppProps } from "next/app";

const httpLink = createHttpLink({
  uri: process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT,
});

const authLink = setContext((_, { headers }) => {
  return {
    headers: {
      ...headers,
      "x-hasura-admin-secret": process.env.NEXT_PUBLIC_HASURA_ADMIN_SECRET,
    },
  };
});

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

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

## おまけ
### ChakraUIの設定
　webコンテナ内から[ChakraUI](https://chakra-ui.com/getting-started/nextjs-guide)をインストールする。
```bash
npm i @chakra-ui/react @chakra-ui/next-js @emotion/react @emotion/styled framer-motion
```

　ChakraUIを利用するため、`_app.tsx`にProviderの設定を行う。
```diff:_app.tsx
+ import { ChakraProvider } from "@chakra-ui/react";

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

## おわりに
　以上でGraphQL環境の構築が完了する。実際にhttp://localhost:3000 にアクセスするとnext.jsに、http://localhost:8080 にアクセスするとHasuraにアクセスが可能。
　では、良いエンジニアライフを。