こんにちは。KOUKIです。
TodoリストアプリケーションをJavaScriptとGo言語で実装しています。
今回は、TodoリストのDocker化とDB切り替え処理の実装を行います。
<目次>
前回
ファイル作成
作業に必要なファイルを作成してください。
1 2 3 4 5 6 7 8 |
touch docker-compose.yml mkdir mysql mkdir docker mkdir docker/ui mkdir docker/api touch docker/ui/Dockerfile touch docker/api/Dockerfile touch api/repository/todo_mysql.go |
Docker化
Dockerを使えるようになると、アプリケーション開発の実行環境を簡単に構築できるようになるので、普段使いすることをお勧めします。
Dockerfile
Dockerfileを作成しましょう。
1 2 3 4 5 6 7 8 9 |
# docker/ui/Dockerfile FROM node:14.9.0-alpine3.10 CMD ["/bin/sh"] WORKDIR /ui RUN apk update && \ npm install -g http-server |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# docker/api/Dockerfile FROM golang:1.15-alpine3.12 RUN apk update && \ apk upgrade && \ apk add git RUN go get github.com/cespare/reflex ENV CGO_ENABLED=0 WORKDIR /go/src/api COPY ./api ./ RUN go mod download |
docker-compose.yml
docker-compose.ymlでは、以下のサービスを定義します。
- apiサービス(golang)
- uiサービス(html/css/javascript)
- mysqlサービス(DBをMySQLへ)
- phpmyadminサービス(DBの視覚化する)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
version: "3" services: api: build: context: . dockerfile: ./docker/api/Dockerfile ports: - 80:80 volumes: - ./api:/go/src/api/ command: > sh -c "reflex -s -r '\.go$$' go run main.go" depends_on: - mysql environment: MYSQL_USER: admin MYSQL_PASSWORD: admin MYSQL_DATABASE: go_todo ui: build: context: . dockerfile: ./docker/ui/Dockerfile ports: - 8080:8080 volumes: - ./ui:/ui command: http-server mysql: image: mysql:5.7.22 environment: MYSQL_ROOT_PASSWORD: admin MYSQL_USER: admin MYSQL_PASSWORD: admin MYSQL_DATABASE: go_todo ports: - "3306:3306" volumes: - ./mysql/data:/var/lib/mysql phpmyadmin: image: phpmyadmin/phpmyadmin environment: - PMA_ARBITRARY=1 - PMA_HOST=mysql - PMA_USER=admin - PMA_PASSWORD=admin links: - mysql ports: - 8888:80 |
動作確認
次のコマンドで、コンテナを立ち上げてください。
1 |
docker-compose up |
コンテナが立ち上がったら、「http://localhost:8080」にアクセスしてください。

OKですね。これで、Docker化が完了です!
MySQLの管理画面にアクセスしたい場合は、「http://localhost:8888」にアクセスしてください。
DB切り替え
以前からGoのInterfaceを使うとDBの切り替えが楽になるとお伝えしてきました。しかし、実際に切り替えたことがありませんでしたw
そこで、MySQLとsync.Mapの切り替えを行ってみたいと思います。
GORM
今回は、MySQLへのアクセスを簡単にするために、GORMを使います。これを使うとSQL文を書く代わりに、GoのコードでMySQLにアクセスできるようになります。
ドメイン
Todoにgormのプライマリキーをつけておきます。
1 2 3 4 5 6 7 8 |
// domain/todo.go package domain type Todo struct { ID int `json:"id" gorm:"primaryKey"` Text string `json:"text"` Completed bool `json:"completed"` } |
レポジトリー
レポジトリーには、MySQLへのアクセスメソッドを定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
// repository/todo_mysql.go package repository import ( "errors" "fmt" "todo/domain" "gorm.io/gorm" ) type todoRepositoryMySQL struct { db *gorm.DB } func NewTodoRepositoryMySQL(db *gorm.DB) domain.TodoRepository { return &todoRepositoryMySQL{ db: db, } } // 全Todo取得 func (t *todoRepositoryMySQL) AllGet() ([]domain.Todo, error) { var todos []domain.Todo // https://gorm.io/ja_JP/docs/query.html#Retrieving-all-objects result := t.db.Find(&todos) if result.Error != nil { return nil, errors.New("Unexpected Error in retrieving all the records ") } return todos, nil } // Todoステータス更新 func (t *todoRepositoryMySQL) StatusUpdate(id int) error { var todo domain.Todo result := t.db.First(&todo, id) if result.Error != nil { return errors.New("Unexpected Error in getting the todo") } // ステータス更新 if todo.Completed { todo.Completed = false } else { todo.Completed = true } result = t.db.Save(&todo) if result.Error != nil { return errors.New("Unexpected Error in updating the todo") } return nil } // Todo保存 func (t *todoRepositoryMySQL) Store(todo domain.Todo) error { result := t.db.Create(todo) if result.Error != nil { return errors.New("Unexpected Error in creating the todo") } return nil } // Todo削除 func (t *todoRepositoryMySQL) Delete(id int) error { result := t.db.Delete(&domain.Todo{}, id) if result.Error != nil { return errors.New("Unexpected Error in deliting the todo") } return nil } // Todo検索 func (t *todoRepositoryMySQL) Search(key string) ([]domain.Todo, error) { var todos []domain.Todo result := t.db.Where("text LIKE ?", fmt.Sprintf("%%%s%%", key)).Find(&todos) if result.Error != nil { return nil, errors.New("Unexpected Error in retrieving search todos ") } return todos, nil } |
GORMを使うと、簡単にMySQLにアクセスできることがわかると思います。
フレームワーク&ドライバー(DB切り替え)
main.goに次の処理を追加します。
- 環境変数からMySQL接続に必要な情報を取得
- DBのスキーマーを作成(マイグレーション)
- MySQL接続
- MySQLレポジトリーをインスタンス化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
// main.go package main import ( "fmt" "os" "todo/delivery" "todo/domain" "todo/repository" "todo/usecase" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "gorm.io/driver/mysql" "gorm.io/gorm" ) // docker-composeファイルから環境変数を取得 var ( schema = "%s:%s@tcp(mysql:3306)/%s?charset=utf8&parseTime=True&loc=Local" username = os.Getenv("MYSQL_USER") password = os.Getenv("MYSQL_PASSWORD") dbName = os.Getenv("MYSQL_DATABASE") datasourceName = fmt.Sprintf(schema, username, password, dbName) ) func connect() *gorm.DB { // mysqlへアクセス connection, err := gorm.Open(mysql.Open(datasourceName), &gorm.Config{}) if err != nil { panic("Could not connect to the database") } // DBのスキーマーを作成 connection.AutoMigrate(&domain.Todo{}) return connection } func main() { // mysqlの接続 db := connect() // mapのrepositoryをインスタンス化 // tr := repository.NewSyncMapTodoRepository() // mysqlのrepositoryをインスタンス化 tr := repository.NewTodoRepositoryMySQL(db) // usecaseをインスタンス化 ... } |
ここでのポイントは、もちろんDBの切り替えです。
「tr := repository.NewSyncMapTodoRepository()」の呼び出しの代わりに「tr := repository.NewTodoRepositoryMySQL(db)」を呼び出すことで、DBを切り替えています。
大変便利ですね。
1点だけ注意点があります。現状の作りだと日本語文字を保存できません^^;
多分、MySQLの設定が足りないのでしょう。
おわりに
Todoリストの作成、クリーンアーキテクチャ設計、DB切り替え、Docker化と色々とやりましたね^^
Todoアプリケーション開発は本記事で終了としますが、アイデア次第で色々な機能を追加できると思うので、ぜひ挑戦してみてください。
それでは、また!
関連記事
こちらの記事も人気です!
コメントを残す
コメントを投稿するにはログインしてください。