概要
留意点
- スライドにもある通り、私がGoに触った時間は当時15時間くらいの超初心者です
- 当時とにかく動く事を第一の目的にして作ったので、まだまだ穴が多いと思っています
前提条件
- バージョンは以下の通りです
- Go:go1.12.6 darwin/amd64
- MySQL:5.7.26
- ローカル環境で実装しました
流れ
- 作ろうとしているものの説明
- GoでMySQLを接続する
- 環境変数を設定する
- SQL接続処理だけ共通ファイルにまとめる
- Json形式で返すWeb APIを作成する
詳細
1. 作ろうとしているものの説明
- 2019年現在の私のマイブームが将棋です(こちらも超初心者です)
- 同僚などと指した際の勝敗結果と内容(戦法/囲い)を管理しようと考えています
- ここでは戦法(英語でopeningというらしい)の一覧取得のみを目指します
- MySQLのデータは以下のようなものを用意しました
-
shogi
データベースの中にopening
テーブルを作成してます
-
+------------+-----------------+
| opening_id | name |
+------------+-----------------+
| 1 | なし |
| 2 | 居飛車棒銀 |
| 3 | 三間飛車 |
| 4 | 四間飛車 |
| 5 | 向い飛車 |
| 6 | 中飛車 |
+------------+-----------------+
2. GoでMySQLを接続する
GoでMySQLに接続する や Package sqlを参考にさせていただきました。
MySQLパッケージのインストール
$ go get -u github.com/go-sql-driver/mysql
MySQLの接続確認
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "****:****@/shogi")
if err != nil {
log.Fatal(err)
}
defer db.Close()
id := 3
var name string
err = db.QueryRow("SELECT name FROM opening WHERE opening_id = ?", id).Scan(&name)
if err != nil {
log.Fatal(err)
}
fmt.Println(name)
}
接続結果
mysqltest $ go build
mysqltest $ ./mysqltest
三間飛車
これで無事取得することができました
環境変数を設定する
DBのパスワードをgit管理内に置いておくのはよくありません。
個人開発ならまだしも、会社でこんなものを書いたら、レビューの嵐ですね。。
.envファイルで設定していきます。
godotenvパッケージのインストール
go get github.com/joho/godotenv
.envの設定
DB_NAME=shogi
DB_ROLE=****
DB_PASSWORD=****
.envをLoadして反映
// "os" "github.com/joho/godotenv" をそれぞれインポートしてください
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
db, err := sql.Open("mysql", os.Getenv("DB_ROLE") + ":"+os.Getenv("DB_PASSWORD") + "@/" + os.Getenv("DB_NAME"))
// 以下割愛
これで、ソースコード内にパスワードを置く必要がなくなりました。
4. SQL接続処理だけ共通ファイルにまとめる
1ファイルだけならこのまま main.go
でいいかもしれませんが、
接続のたびに毎回接続処理を書くのは正直よくありません。
接続処理だけ切り出し、main.goではそれを呼び出すだけにします。
処理のファイルの置き場所を決める
project-layout を読んだ結果 、 pkg/
配下に置くことにしました。
共通処理にして切りだす
SQLを接続して、成功した場合にDB型を返すようにします
func Connect() *sql.DB {
err := godotenv.Load()
if err != nil {
panic(err.Error())
}
db, err := sql.Open("mysql", os.Getenv("DB_ROLE") + ":"+os.Getenv("DB_PASSWORD") + "@/"+os.Getenv("DB_NAME"))
if err != nil {
panic(err.Error())
}
return db
}
共通処理を呼び出す
データの取得処理自体も pkg/dao/opening/openingdao.go
としてで切り出します。
(これは共通処理というよりビジネスロジックから切り離そうとした結果です)
データを構造体のスライスに格納して返すようにします。
package openingdao
import (
"github.com/hunhunyosshy/black-and-white/pkg/db"
)
//Opening型の構造体を用意します
//あとでjson形式にするので、jsonのタグをあらかじめつけておきます
type Opening struct {
ID int `json:"id"`
Name string `json:"name"`
}
func FetchIndex() []Opening {
db := db.Connect()
defer db.Close()
//rowを取得
rows, err := db.Query("SELECT * FROM opening")
if err != nil {
panic(err.Error())
}
//Opening型のスライスに格納します
openingArgs := make([]Opening, 0)
for rows.Next() {
var opening Opening
err = rows.Scan(&opening.ID, &opening.Name)
if err != nil {
panic(err.Error())
}
openingArgs = append(openingArgs, opening)
}
return openingArgs
}
5. Json形式で返すWeb APIを作成する
APIとして使えるよう、URIを叩けばJson形式にして返すようにします。
今回は、ルーティング処理を、gorilla/mux というライブラリでやってみました。
(ちなみに採用理由は昔ゴリというあだ名をつけられていて、親近感が湧いたためです)
gorilla/mux パッケージのインストール
go get -u github.com/gorilla/mux
Json形式で返すようにする
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
openingdao "github.com/hunhunyosshy/black-and-white/pkg/dao/opening"
)
func main() {
r := mux.NewRouter()
// localhost:8080/opening/ で戦法の一覧を取得できるようにします
r.HandleFunc("/opening/", showOpeningIndex)
log.Fatal(http.ListenAndServe(":8080", r))
}
func showOpeningIndex(w http.ResponseWriter, r *http.Request) {
opening := openingdao.FetchIndex()
//json形式に変換します
bytes, err := json.Marshal(opening)
if err != nil {
log.Fatal(err)
}
w.Write([]byte(string(bytes)))
}
実際に返すか確認する
無事返すことができました。めでたしめでたし
まとめ(というか感想?)
- 色々ハマったが、ひとまず簡単なWEB APIを作れるようにはなった気がする
- 環境変数の設定、jsonへの変換は比較的楽だった
- ライブラリは有効活用できるかは、公式ドキュメントをどれだけ読み込めるかによる
- もし会社でやるなら、ライブラリの技術選定は大事になる気がする
- まだまだまとめられることはあると思うので、引き続き実装していきたい
参考にしたリンク
GoでMySQLに接続する
Package sql
インポート宣言
pkgの説明
Goにはディレクトリ構成のスタンダードがあるらしい。
Go 言語で gorilla/mux を使った簡単なウェブアプリのサンプル
Go言語でServer作る時に必要な知識メモ