【ハンズオン】Next.js × Go × AWSでJWT認証付きGraphQLアプリとCI/CDを構築してみよう

# 目次

:::note info
■ご案内■
本内容は合計４つの記事で構成されています。

- **[【環境構築編】](https://qiita.com/WebEngrChild/items/d4bc23bf352e7aa46361)** 　👈いまここです
- [【Next.js編】](https://qiita.com/WebEngrChild/items/6e9e3232046301879089)
- [【Go編】](https://qiita.com/WebEngrChild/items/d9b87944235c5220ae5b)
- [【AWS編】](https://qiita.com/WebEngrChild/items/ca93783f8ae6bee7f985)

これからも頑張ってハンズオン系の記事を書いていきたいと思っているので、いいねっと思って頂けたら**LGTM**押していただけると励みになります！

:::

# 作成に至った背景

普段エンジニアの皆さんは、業務用に新しいライブラリやツールを調べたり、趣味で新しい言語やフレームワークを使ってサンプルアプリを作ってみる方は多いと思います。

エンジニアになって歴は浅いものの、私も例に違わず、業務前後や休日を使って趣味の延長でコードを書いていました。

**ある日、ふと自分のGitHubリポジトリを見返してみると、それなりに多くの"インプットの跡"に気づきました。**


"使えそうなプロジェクトを合体"してみれば、それなりのボリュームにもなるし、何より<INS>GitHubの藻屑となりえたこの子達にも少しは光が当たるのでは...</INS>」という考えに至りました。

上記が本記事作成の背景です。

お見苦しい内容ではありますが、エンジニア転職や個人開発、同スタックを用いたアプリケーション開発の参考になれば幸いです。

:::note warn
その時々の個別コンテキストによって生み出された複数のプロジェクトたちを、半ば強引に統合した形ではあるため、寛大なお心でご覧ください。
:::

# 想定読者と進め方

対象となる読者は、以下を想定しています。

:::note info
対象者
- Next.js(Tanstack Query/Code Generator) × Go(echo/gqlgen) × AWS(ECS/CodePipeline)という技術スタックに何かしら興味を持たれた方
- 転職や就職でポートフォリオを作成するための"たたき台"を探している方
- 説明が省略されている箇所はソースコードを追っていただける方
:::

また、本記事の主目的は、<font color="RoyalBlue">このサンプルアプリケーションで利用したライブラリ、ツールの紹介</font> がメインとなっています。

そのため文量の兼ね合いもあり、<INS>実際のコードをかなり割愛して説明</INS>しています。

読み進めて頂ける方は、ぜひGitHubよりプロジェクトをクローン頂き、その都度お手元で確認頂けると嬉しいです。

# ハンズオンで作成できるアプリケーションの概要

よくあるTODOアプリというかTwi○terの紛いものような、非常にシンプルなサンプルアプリです。

フロントエンドは`Next.js`, バックエンドは`Go`, ローカル開発環境は`Docker/DockerCompose`, 本番環境は`AWS(ECS/CodePipeline)`を利用しています。

また、本記事ではドメイン取得、並びにALBとの紐付けまで紹介します。最終的にAWSへデプロイを行い、ドメイン指定でアクセスできるところまで行っていきます。

合計で以下3つの記事で構成されます。

## Next.js編

- Yarn3(PnP/Zero-Installs)を使ったパッケージ管理
- GitHubActionsでCI実行
- ESLint/Prettierを使った静的解析
- Recoilを使ったグローバル状態管理
- GraphQL Code Generatorを使ったスキーマ管理
- TanStack Queryを使ったデータフェッチ
- msw/React-testing-libraryを使ったテスト
- ..etc

## Go編

- クリーンアーキテクチャ風なディレクトリ設計
- GitHubActionsを用いたCI環境構築（golangci）
- Echoフレームワーク
- JWT認証
- Gooseを使ったマイグレーション管理
- GORMを使ったDB操作
- gqlgenを利用したGraphQLのスキーマ駆動開発
- N+1対策のDataLoader
- Sentryを使ったエラー通知
- Go Mockを使ったテスト
- ..etc

## AWS編

- ECS on Fargate
- ECR
- CodeBuild（hadolint/dockle/trivyで脆弱性チェック）
- CodeDeploy（Blue/Greenデプロイ）
- RDS
- Route53/ACM
- IaC
- ..etc

## デモ
![画面収録-2023-05-15-7.31.00.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1824740/308b6e74-ee39-83aa-70d6-851ffd5d2104.gif)

## インフラ構成図
![インフラ構成ず.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1824740/89ffd95e-7e91-19f2-f2e1-57d7f257be68.png)

# 環境構築

念の為、この記事を作成している筆者のローカル環境を以下に掲載しておきます。

|項目  |内容  |
|---|---|
|PC  |M1 MacBook Pro（14インチ、2021）|
|OS  |MacOS Monterey|
|IDE（統合開発環境）  |Visual Studio Code, GoLand|

:::note warn
ご注意ください
   `Windows`やIntelチップ製の`Mac`での動作検証は行っておりませんのでご容赦ください。
:::

上述の通り、文量の兼ね合いから全てのコードを一行ずつ説明することはできません。したがって、お手元のローカル環境にgithubよりクローンをして不足箇所は都度ご確認いただけると幸いです。

## Repositoryクローン

```shell:Terminal
# API
$ git clone git@github.com:WebEngrChild/go-graphql-jwt-api.git

# Front Application
$ git clone git@github.com:WebEngrChild/next-graphql-front.git
```

https://github.com/WebEngrChild/next-graphql-front

https://github.com/WebEngrChild/go-graphql-jwt-api

`next-front-app`において、`VsCode`では以下のようなエラーが発生する場合があります。画像を参考にワークスペースで指定されているTypeScriptのバージョンを許可頂くと解消されます。

![スクリーンショット 2023-05-19 6.24.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1824740/fa0b9dee-6b9e-d8eb-b6d2-2c62dac4f2cd.png)

## mkcertを用いたSSLサーバ証明書発行

mkcertというライブラリを使うと、簡単に証明書を発行してhttps環境を構築することができます。
本実装は`next-front-app`に設定ファイルがあります。

```shell:Terminal
# インストール
$ brew install mkcert

# ルートCAの生成とインストール
$ mkcert -install
> Sudo password:

# SSL証明書と秘密鍵を生成
$ pwd
> /Users/name/sandbox/next-front-app
$ mkdir .docker/nginx/cert
$ mkcert -cert-file .docker/nginx/cert/localhost.pem -key-file .docker/nginx/cert/localhost-key.pem localhost

```

ここでは`nginx`をリバースプロキシサーバーとして配置しております。

```config:next-front-app/.docker/nginx/conf.d/default.conf
server {
    # フロントエンド
    listen 3443 ssl;
    server_name localhost;
    ssl_certificate /etc/certs/localhost.pem;
    ssl_certificate_key /etc/certs/localhost-key.pem;
    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://172.30.0.10:3000/;
    }
    # devモードでのコード編集時のホットリロード (HMR)Error対策
    location /_next/webpack-hmr {
        proxy_pass http://172.30.0.10:3000/_next/webpack-hmr;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
server {
    # バックエンド
    listen 8443 ssl;
    server_name localhost;
    ssl_certificate /etc/certs/localhost.pem;
    ssl_certificate_key /etc/certs/localhost-key.pem;
    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://172.30.0.2:8080/;
    }
}
```

https://qiita.com/rkunihiro/items/530b5dc685bd3bff2082

## Docker初期セットアップ

### Network作成

```shell:Terminal
$ docker network create --subnet=172.30.0.0/24 sample_graph_network
```

### フロント

```shell:next-front-app/
# .env.local生成
$ pwd
> /src
$ cp .env.development .env.local

# next-front-appのルートで実行
$ make init
$ make build-app
$ make start-app

> docker-compose exec front yarn start
> ready - started server on 0.0.0.0:3000, url: http://localhost:3000
```

### API

※API側は別途`【Go編】`にて説明いたしますので、ここでは説明を割愛いたします。

```shell:/go-graphql-jwt-server
# go-graphql-jwt-serverのルートで実行
$ cp .env.example .env
$ make init

# マイグレーション実行
$ maket migrate # init実行後にmysqlコンテナが立ち上がり切るまで時間がかかるので少し時間を空けてください

> 2023/05/18 03:03:20 OK    20221208215239_createmessages.sql
> 2023/05/18 03:03:20 OK    20221210225619_createusers.sql
> 2023/05/18 03:03:20 goose: no migrations to run. current version: 20221210225619

# APIサーバー起動
$ make start

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.9.0
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8080
```

## 動作確認

ブラウザからhttps://localhost:3443 にアクセスしてログイン画面で以下項目を入力して、
一覧画面に遷移できたら完了です。

|項目  |内容  |
|---|---|
|email  |test1@example.com|
|password  |password1|

![画面収録-2023-05-15-7.31.00.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1824740/308b6e74-ee39-83aa-70d6-851ffd5d2104.gif)

# この後は

:::note info
■ご案内■

- [【環境構築編】](https://qiita.com/WebEngrChild/items/d4bc23bf352e7aa46361)　
- **[【Next.js編】](https://qiita.com/WebEngrChild/items/6e9e3232046301879089)** 　👈次はこちらへ
- [【Go編】](https://qiita.com/WebEngrChild/items/d9b87944235c5220ae5b)
- [【AWS編】](https://qiita.com/WebEngrChild/items/ca93783f8ae6bee7f985)

これからも頑張ってハンズオン系の記事を書いていきたいと思っているので、いいねっと思って頂けたら**LGTM**押していただけると励みになります！

:::