APIを作りながら進むGo中級者への道を写経するリポジトリ
内容差分
asdf
を使っている。そのせいか、go.mod
およびgo.sum
の記述によってvscode上でエラーが発生することがある
Command 'gopls.go_get_package' failed: Error: err: exit status 1: stderr: go: finding module for package <ローカルのパッケージ>
gopls
のエラーだが、どうやらasdf
のgolangのpkg
にインストールされたパッケージを見にいったりしている?
こういう場合、go.mod
とgo.sum
のそれっぽいパッケージの部分を削除し、コードでimportしてるそれっぽいパッケージの部分も削除。vscodeのGolang拡張機能が入っていれば、そのまま保存すれば現在参照できる形で勝手に修正され、エラーは消えた。
特に最初はちょこちょこハンドラやリクエストの扱いなどを変更 -> プロセスを停止させたあと go run main.go
で再度起動し別ターミナルでcurlで確認、という工程が多い。air
でホットリロードすることにした
go install github.com/cosmtrek/air@latest
air
__ _ ___
/ /\ | | | |_)
/_/--\ |_| |_| \_ v1.49.0, built with Go go1.21.4
- これにより
go run main.go
時にオプションを渡すなどができなくなる
本書だとよく「最初のAPI用のコードだけ書いて、あとは実戦演習」のように進む。そのとき、全部のAPIを書かずとも、ひとつひとつ完成したところから試せるのがよい(ただしhandler-serivice-repositoryが揃ったp241以降だが)
本書ではgo run
時にDBのパスワードなどをオプションで渡し、コードでos.Getenv
で読み取るのだが、自分の環境ではうまくいかず。環境変数としてオプションを渡す方法は情報がなく不明。
これはjoho/godotenv
を使うことにした
func init() {
// 本書で書かれていた「実行時に環境変数をオプションで渡す」が動かなかったのでgodotenvで読み込むことにした
err := godotenv.Load(".env")
if err != nil {
log.Fatal(err)
}
}
// var (
// dbUser = os.Getenv("DB_USER")
// dbPassword = os.Getenv("DB_PASSWORD")
// dbDatabase = os.Getenv("DB_NAME")
// dbConn = fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s?parseTime=true", dbUser, dbPassword, dbDatabase)
// )
func main() {
dbUser := os.Getenv("DB_USER")
dbPassword := os.Getenv("DB_PASSWORD")
dbDatabase := os.Getenv("DB_NAME")
dbConn := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s?parseTime=true", dbUser, dbPassword, dbDatabase)
書籍内ではMySQLのDockerコンテナをローカルにあるmysql
コマンド経由で使っている。自分の環境ではローカルにMySQLがないので、コンテナのシェルに入って直接操作している。
services:
mysql:
platform: linux/x86_64 <- M1 mac用
...各種設定
volumes:
- db-volume:/var/lib/mysql
- ./createTable.sql:/docker-entrypoint-initdb.d/createTable.sql <- これを追加した
本書どおりにDBからテーブルを確認する。上記のdocker-compose.yaml
の追記は、コンテナボリュームが作成されるときに実行されるので、すでに作っていた場合はコンテナごと削除して再度作り直します
docker-compose down -v
docker-compose up
別のターミナルからコンテナに入って確認
docker exec -it db-for-go /bin/sh
mysql -u docker sampledb -p
/usr/bin/mysql: /usr/bin/mysql: cannot execute binary file
となる場合は以下を試す
docker exec -it db-for-go mysql -u docker -p
p224のexec.Command
について、環境の違いで改変。本書の環境だとmysql
がローカルにある前提なので、
cmd := exec.Command("mysql", "-h", "127.0.0.1", "-u", "docker", "sampledb",
↪ "--password=docker", "-e", "source ./testdata/cleanupDB.sql")
のようになっている。自分の環境ではDocker
のMySQLコンテナ上でDBを動かしているが、exec.Command
みたいに実行しようとしても、シェル環境ではないので、リダイレクトができない
// これはリダイレクト演算子をつかっているのでエラーになる
cmd := exec.Command("docker", "exec", "-i", "db-for-go", "mysql", "-udocker", "-pdocker", "sampledb", "<", "./dataset/setupData.sql")
ということでChatGPTに聞いたら、cmd.Stdin
を使って標準入力でファイルを読み込ませろとのこと。
// cmd := exec.Command("mysql", "-h", "127.0.0.1", "-u", "docker", "sampledb", "--password=docker", "-e", "source ./testdata/setupDB.sql") ローカルのmysql経由で実行(本書通り)
// 以下,自分の環境用に改変
// dockerのmysqlコンテナ経由で実行(リダイレクトはシェルの機能でありexec.Commandでは使えない)
setupSql, err := os.Open("./testdata/setupDB.sql")
if err != nil {
return err
}
cmd := exec.Command("docker", "exec", "-i", "db-for-go", "mysql", "-udocker", "-pdocker", "sampledb")
// リダイレクト
cmd.Stdin = setupSql
err = cmd.Run()