TypeScript & GraphQL でToDoアプリを開発する #2
⬅️前回の記事はこちら
⭐️バックエンドのセットアップ
backend/に移動
% cd ../backend
Node.jsプロジェクトを初期化
% npm init -y
本番用の依存関係をインストール
- express@4:Node.js用のWebフレームワーク
- dotenv:.envに設定したポートやキー等を読み込む
- cors:APIをフロントエンドから安全に呼び出す
- @apollo/server & graphql & graphql-tag:GraphQLを使うために必要
% npm install express@4 dotenv cors @apollo/server graphql graphql-tag
開発用の依存関係をインストール
- typescript:.tsを.jsに変換(トランスパイル)する
- ts-node-dev:.tsをリアルタイムで実行・再起動できる
- @types/node:Node.jsの型定義 TypeScriptでfs,Path,process 等を使う場合に必要
- @types/express@4:Expressの型定義 TypeScriptでreq,res,next 等を使う場合に必要
- @types/graphql:GraphQLの型定義 GraphQLや型を扱う場合に必要
- @types/cors:corsの型定義
% npm install -D typescript ts-node-dev @types/node @types/express@4 @types/graphql @types/cors
TypeScriptプロジェクトに必要なtsconfig.jsonを作成
% npx tsc --init
backend/の中身を見て、バックエンドの雛形が作られていることを確認
% tree -L 1
.
├── node_modules
├── package-lock.json
├── package.json
└── tsconfig.json
Node.jsにPrisma(ORM)をインストール
- 開発中に必要なPrisma CLIをインストール
% npm install -D prisma
- Prismaが生成するDBクライアントをインストール
% npm install @prisma/client
Prismaを初期化
% npx prisma init
backend/に下記ファイル、フォルダが作られたのを確認
backend/
├── prisma/
│ └── schema.prisma // DBスキーマ定義ファイル
├── .env // 環境変数定義ファイル
作られたschema.prismaを確認
generator client { // Prismaにどんなコードを生成するかを定義するブロック
provider = "prisma-client-js" // Prisma公式の JavaScript & TypeScript 用クライアントを使う
output = "../generated/prisma" // コードを生成する出力先ディレクトリを指定(通常は node_modules/@prisma/client に出力されるらしいのでこの記述は削除する)
}
datasource db { // どのDBに接続するかを定義するブロック
provider = "postgresql" // 使用するDB(今回は postgresql を指定)
url = env("DATABASE_URL") // .envのDATABASE_URLに記載された接続先DBのURLを使う
}
下記のように修正
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Todo { // モデル(Todoテーブル)をどのように設計するかを定義するブロック
id Int @id @default(autoincrement()) // idカラム、主キー、1ずつ増える
title String // titleカラム
completed Boolean @default(false) // completedカラム、初期値にfalse
createdAt DateTime @default(now()) // createdAtカラム、初期値に現在日時
}
作られた.envを確認
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
自身の環境に合うように修正
DATABASE_URL="postgresql://<POSTGRES_USER>:<POSTGRES_PASSWORD>@localhost:<PORT>/tododb?schema=public"
DB用のdocker-compose.ymlをTypeScript-ToDo/に作成
version: "3.8" // Docker Composeのバージョン指定
services: // コンテナとして動かすサービスを定義する 今回はdbという名前のサービスを定義している
db: // サービス名
image: postgres:15 // PostgreSQL v15 の公式イメージ
restart: always // コンテナが停止するたびに自動的に再起動する
environment: // 環境変数を定義する
POSTGRES_USER: <POSTGRES_USER> // <POSTGRES_USER>を.envのDATABASE_URLの値と紐づける
POSTGRES_PASSWORD: <POSTGRES_PASSWORD> // <POSTGRES_PASSWORD>を.envのDATABASE_URLの値と紐づける
POSTGRES_DB: tododb // tododbを.envのDATABASE_URLの値と紐づける
ports:
- "<PORT>:5432" // <PORT>を.envのDATABASE_URLの値と紐づける(ホストの<PORT>にアクセスすると、コンテナ内のPostgreSQL[5432]に届く)
volumes:
- db_data:/var/lib/postgresql/data // 永続化ストレージの設定 ホスト側のdb_dataという名前のボリュームを使って、指定したディレクトリにマウント
volumes: // db_dataボリュームの定義
db_data: // ボリュームに名前を設定する
コンテナを起動
% docker-compose up -d
DBの接続を確認
※下記コマンドを実行後にパスワードを求められるので、<POSTGRES_PASSWORD>を入力
※確認後はexit
% psql -h localhost -p <PORT> -U <POSTGRES_USER> -d tododb
Prismaでマイグレーションを実行
% npx prisma migrate dev --name init
backend/prisma/に下記ファイル、フォルダが作られたことを確認
backend/prisma/
├── migrations/ // マイグレーション履歴を管理するフォルダ
├── 20250601134440_init/ // スキーマ変更の内容が格納されるフォルダ
│ └── migration.sql // DBに実行される具体的なSQL文(今回はCREATE TABLE)が書かれたファイル
└── migration_lock.toml // マイグレーションの状態を管理するためのロックファイル
🚀バックエンドのセットアップが完了!!!
#2のおわりに
バックエンドのセットアップ お疲れさまでした。
次回からは Apollo Server & Apollo Client の起動 に入っていきます。
〜details tododb(データベース) と db_data(ボリューム)の違いについて〜
◼️tododb
tododbはPostgreSQLの中で使われる、SQLで操作する対象のデータベース名です。
CREATE DATABASE tododb;
上記のような操作をDockerコンテナ起動時に自動的に行うのが下記の定義です。
environment:
POSTGRES_DB: tododb
◼️db_data
Dockerが管理する、PostgreSQLの物理ファイルが保存される場所(ボリューム)の名前です。
下記の設定により、PostgreSQLのデータが保存される物理フォルダ(/var/lib/postgresql/data)をボリュームにマウントします。
volumes:
- db_data:/var/lib/postgresql/data
◼️なぜdb_dataで永続化するの?
Dockerコンテナは一時的な実行環境であり、頻繁に作り直すことがあります。
しかし、コンテナを削除するとDB情報(ユーザー情報、テーブル、データ 等)も全て失われてしまいます。
そこで、db_data(ボリューム)を定義しておくことで、コンテナが削除されてもDB情報がホスト側に保持されます。(ボリュームにマウントをすることでバックアップが可能)
新しいコンテナを作る際に、同じdb_dataを定義すればDB情報が復活します。(リストアが可能)
Discussion