Next.js, Prisma, PostgreSQL, Dockerによるフルスタックアプリケーションの環境構築

# はじめに
前回、DockerによるNext.jsの環境構築について投稿させていただきました。

https://qiita.com/higemegane1992/items/defd193f4c8752ca9996

本投稿では、さらにPrismaとPostgreSQLを用いて、フルスタックアプリケーションの環境構築について記載させていただきます。
[こちらの記事](https://vercel.com/guides/nextjs-prisma-postgres "How to Build a Fullstack App with Next.js, Prisma, and PostgreSQL")のStep3までを、Dockerを用いた内容に変更して書き起こしております。
前回記事の内容と重複する部分もございますが、大多数の方は前回記事はご覧になられていないと思いますので、初めから順を追って記載させていただこうと思います。

# DockerによるNext.jsの環境構築
ここでは、DockerでのNext.js単体の環境構築について記載させていただきます。[前回記事](https://qiita.com/higemegane1992/items/defd193f4c8752ca9996 "DockerによるNext.jsの環境構築 - Qiita")をご覧になられた方は、[Prismaのインストール](https://qiita.com/higemegane1992/items/f933209de3015ccb888e#prisma%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB "Prismaのインストール")まで読み飛ばしてください。

## Dockerfileの作成
```dockerfile:Dockerfile
FROM node:17.6.0

WORKDIR /usr/src/app

RUN npm install -g npm@latest && npm install create-next-app
```
上記のDockerfileにより実行されるのは、下記の3点です。
1. 公式のnodeイメージを使用
2. 作業ディレクトリを定義
3. create-next-appをインストール

## docker-compose.ymlの作成
```yml:docker-compose.yml
version: "3.9"
services:
  app:
    build: .
    volumes:
      - .:/usr/src/app
    ports:
      - "3000:3000"
    command: bash -c "npm run dev"
```
docker-compose.ymlでは下記を実行します。
1. 先ほどのDockerfileを参照
2. Next.jsアプリケーションを展開するディレクトリにマウントを作成
3. create-next-appのデフォルトのポートに接続
4. 開発モードでの起動

## Next.jsアプリケーションの作成
初めに、イメージのビルドを行います。
```terminal:terminal
docker-compose build
```
次に、create-next-appによりNext.jsアプリケーションを作成します。
展開用のディレクトリにルートを指定すると、Dockerfileとdocker-compose.ymlによりコンフリクトが発生するため、
ここでは一時的にtmpディレクトリに作成し、ルートへ移動しています。
```terminal:terminal
docker-compose run --rm app npx create-next-app tmp --ts\
&& mv tmp/* . && mv tmp/.* . && rm -r tmp
```
:::note info
補足
--tsはTypescriptでのNext.jsアプリケーションの作成を指定しています。Javascriptでの開発を希望される方は、省略してください。
:::
最後に、コンテナを起動します。
```terminal:terminal
docker-compose up
```
[http://localhost:3000](http://localhost:3000 "Create Next App")が正常に起動していれば成功です。

# Prismaのインストール
npmによりPrismaのインストールを行います。
```terminal:terminal
docker-compose exce app npm install prisma --save-dev
```
続いて、下記のコマンドでPrismaの基本的なセットアップを行います。
```terminal:terminal
docker-compose exce app npx prisma init
```
ここでは、下記を実行しています。
1. `prisma/schema.prisma`の作成
2. `.env`の作成

忘れずに、`.env`を`.gitignore`に追加しましょう。

```diff_yaml:.gitignore
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
+ .env
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel

# typescript
*.tsbuildinfo
```

# PostgreSQLとの接続
最後にDocker ComposeによりPostgreSQLと接続を行います。

## docker-compose.ymlの修正
```diff_yaml:docker-compose.yml
version: "3.9"
services:
  app:
    build: .
    volumes:
      - .:/usr/src/app
    ports:
      - "3000:3000"
    command: bash -c "npm run dev"
+  db:
+    image: postgres:14.2
+    volumes:
+      - ./db:/var/lib/postgresql/data
+    env_file:
+      - .env
+    ports:
+      - "5432:5432"
```
ここで実施しているのは下記の4点です。
1. PostgreSQLの公式イメージの使用
2. データベースへの変更を永続化するための、ボリュームのマウント
3. `.env`ファイルの読み込み
4. PostgreSQLのデフォルトのポートとの接続

## .envファイルの修正

```diff_yaml:docker-compose.yml
- # Environment variables declared in this file are automatically made available to Prisma.
- # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
- 
- # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview).
- # See the documentation for all the connection string options: https://pris.ly/d/connection-strings
- 
+ POSTGRES_PASSWORD="password"
+ POSTGRES_USER="postgres"
- DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
+ DATABASE_URL="postgresql://postgres:password@db:5432/postgres?schema=public"
```
ここでは`docker-compose.yml`で参照するための環境変数(POSTGRES_PASSWORD, POSTGRES_PASSWORD)と`prisma/schema.prisma`で参照する環境変数(DATABASE_URL)を定義しています。

:::note warn
注意
POSTGRES_PASSWORDとPOSTGRES_PASSWORDの値を変更すると、DATABASE_URLの値も変更する必要があるため、ご注意ください。DATABASE_URLの設定については、[Prisma公式のクイックスタート](https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/connect-your-database-typescript-postgres#connect-your-database "Connect your database | Prisma Docs")をご参照ください。
また、DATABASE_URLの`db`は、docker-compose.ymlで指定したPostgreSQLのサービス名と統一してください。
:::

## .gitignoreの修正
```diff_yaml:.gitignore
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel

# typescript
*.tsbuildinfo

+ # database
+ db
```
ここでは、`docker-compose.yml`内で定義したボリュームを`.gitignore`に追加しています。

## 動作確認
```terminal:terminal
docker-compose build
docker-compose up
```
により、アプリケーションを起動します。

次に、PrismaとPostgreSQLの接続の確認のため、`prisma/schema.prisma`からテーブルを作成します。
```diff_yaml:prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

+ model Post {
+   id        Int     @default(autoincrement()) @id
+   title     String
+   content   String?
+   published Boolean @default(false)
+   author    User?   @relation(fields: [authorId], references: [id])
+   authorId  Int?
+ }
+ 
+ model User {
+   id            Int       @default(autoincrement()) @id
+   name          String?
+   email         String?   @unique
+   createdAt     DateTime  @default(now()) @map(name: "created_at")
+   updatedAt     DateTime  @updatedAt @map(name: "updated_at")
+   posts         Post[]
+   @@map(name: "users")
+ }
```
ここでは、PostテーブルとUserテーブルの作成をしています。
```terminal:terminal
docker-compose exec app npx prisma db push
```
により、正常にテーブルが作成されればPrismaとPostgreSQLが接続されていることがわかります。

お好みのSQLクライアントでもデータベースの状態は確認いただけますが、Prismaを利用している場合、下記コマンドからもデータベースの状態をご確認いただけます。
```terminal:terminal
docker-compose exec app npx prisma studio
```

# おわりに
参考までに、本記事の内容のGithubリポジトリも掲載いたしますので、必要な方はご覧ください。

https://github.com/higemegane1992/tone/tree/BuildAFullstackAppWithNext.js%2CPrismaAndPostgreSQL