React + Go + PostgreSQL でアプリの開発環境を作る

はじめに

表題のとおり、Docker で React + Go + PostgreSQL を組み合わせたアプリの開発環境を作ってみたので、その手順を書き残しておく

前提

以下のツールはあらかじめインストールしておくこと

  • docker (docker desktop)
  • go
  • node.js
  • npm
  • postgresql (psql)
  • java

Windows で試す場合は WSL と ubuntu もインストールして、ubuntu で作業すれば構築できた

手順

以下の手順内のコマンドは基本的にプロジェクトのルート(reactapp.comフォルダ)から始めるように書いている

フォルダ移動が必要な場合は都度 cd コマンドも書いているので、見落とさないように注意してほしい

Reactインストール

まず React アプリを生成する

アプリ名は reactapp.com で生成してからフォルダ名を app に変更する
create-react は node はバージョン 14以上が必要になる

React アプリの初期画面を確認したら React は停止する(CTRL+C)

Reactコンポーネント開発

React コンポーネントは storybook で確認しながら作る

Storybookインストール

app フォルダに移動してから storybook と material-ui をインストールする

コンポーネント作成

HelloWorld.tsx と HelloWorld.stories.tsx を作る

app/src/components/HelloWorld.tsx

app/src/components/HelloWorld.stories.tsx

storybook起動

起動したら storybook にアクセス( http://localhost:6006/ )して、HelloWorld コンポーネントを確認する

PUSH ボタンを押すと 1秒後に表示が OK に変わる

コンポーネント開発はこれで完了(ソースコードの説明は省く)

storybook は停止する(CTRL+C)

API設計

OAS (Open API Specification) で API を設計して、prism でモックサーバを作成する

OAS作成

まず、api.yaml を作成する

api/spec/api.yaml

モックサーバ起動

OAS から prism でモックサーバを起動する

モックサーバが起動したらブラウザで http://localhost:3001/message/1 へアクセスすると、{"text":"Bonjour!"} が表示される(OAS に設定した Example がそのまま返ってくる)

モックサーバは起動したまま、次に進む

Reactアプリ開発

コンポーネントを組み合わせ、モックサーバの API を呼びながら React アプリを開発する

API クライアントコード生成

まず、React で使う API クライアントコードを、OAS から生成する(コードは ./app/src/api に出力する)

パッケージインストール

HTTP クライアントに axios を、ルーティングに react-router-dom を使うので、app にインストールする

ページ実装

HelloWorld コンポーネントを使ってページ HelloWorldPage.tsx を作る

app/src/pages/HelloWorldPage.tsx

また、HelloWorldPage.tsx をホームページにするために App.tsx の内容を書き換える

app/src/App.tsx

React起動

React を起動して、PUSH ボタンの動作を確認する

PUSH ボタンを押すとモックサーバの API を呼び出し、レスポンス {"text":"Bonjour!"} の text をボタンに表示する

React アプリ開発はこれで完了。モックサーバと React は停止する(CTRL+C)

データベース

API 開発の前にデータベースを用意する

PostgreSQLコンテナ

Dockerfile と docker-compose を用意する

db/Dockerfile

docker-compose.yml

コンテナを起動する

マイグレーション

migrate モジュールを使ってデータベースに message テーブルを作成する

まず、up と down のファイルを作る

db/migration/0001_create_message_table.up.sql

db/migration/0001_create_message_table.down.sql

migrate をインストールして、マイグレーションを実施する

サンプルデータ

psql コマンドでサンプルデータを投入する

db/sample/sample.sql

確認

DBeaverTablePlus を使って DB に接続して、データを確認する

Name Value
Host localhost
Port 5432
User pguser
Password password
Database reactapp

DB コンテナは API 開発で使うので、起動したまま次に進む

API開発

コンテナのDBを使いながら、go で API を実装する

SQLBoiler

まず、SQLBoiler でデータベースの ORM コードを生成する

設定ファイルを作成して、

db/config/database.toml

sqlboiler でコードを生成する

コードは api/sqlboiler/models に出力される

oapi-codegen

次は oapi-codegen で OAS から API のコードを生成する

出力先フォルダ api/oapi/codegen は先に作っておく

API実装

以下の 4つのファイルを作成する

api/main.go

api/oapi/handler.go

api/oapi/get_message.go

api/oapi/get_message_test.go

go mod tidy で使用している go のモジュールをすべてインストールする

ユニットテスト実施

以下のように出力されれば OK

API 実装はこれで完了。DB コンテナはいったん停止する

Dockerコンテナ

React アプリと API サーバも Docker コンテナで動かして、アプリ全体を結合する

Reactコンテナ

React コンテナの Dockerfile を作成する

app/Dockerfile

APIコンテナ

API コンテナの Dockerfile を作成する

api/Dockerfile

docker-compose

React サーバと API サーバを docker-compose に追加する

docker-compose.yml

コンテナ起動

すべてのコンテナをビルドして、起動する

確認

ブラウザでアプリ( http://localhost:3000/ )にアクセスする
PUSH ボタンを押すと API を介して DB からメッセージデータを取得して、1秒後に Hello World! とボタンに表示される

以上で、React ⇔ API ⇔ DB がそれぞれ連携したアプリがすべて Docker コンテナで動作する環境が出来上がった

おわりに

ちなみにローカルのコードを修正してもコンテナには反映されないので、コンテナ停止してビルドして再起動しなければならない

なので、コンポーネント/React アプリ/API はそれぞれ独立して開発して、コンテナは結合しての動作確認に使う、ということになる? それはそれで面倒な気がする

それと、この環境だと API が CORS に引っかかって Cookie や Session が使えない。対応方法は下の記事を参照してほしい

SPAでCORSに対応してCookieを使えるようになるまで