icon

Blog

本ブログのバックエンドをGo + MySQLで作った

2022/01/11

前回に続き、このブログのデータをFirebaseから自前のMySQLに引っ越ししたのでそれを編集するためのバックエンドAPIを作った。その中で学んだことをまとめておく。


やったこと

  • もともとFirabase storeを使っていたブログのエディターアプリhttps://92thunder.dev/apiを使うよう変更
  • nginxで /apihttp://localhost:1323 にプロキシする
  • バックエンドAPIをGo言語でEchoというフレームワークを使って実装
  • ブログデータをFirestoreからMySQLに愛をこめて手動引っ越し

ブログエディターの変更

  • 保存処理はRepositoryにまとめておいたので影響箇所を少なく抑えられた
  • FirestoreからMySQLのフォーマットに合わせた日付の型に変更した
    • JSは日付のフォーマット面倒
  • APIクライアントライブラリにkyを使ったがとてもシンプルで良さげだった
    • 後からapiClientにheaderの設定が出来ないなど不便なところもあるのかもしれない

バックエンドAPIの認証

誰にでもブログをいじれると困るので認証を入れた。今回はこちらを参考にさせてもらってワンタイムパスワードを使った認証にした。ワンタイムパスワードってOTPって略すんだね。

サーバ起動時にOTPのシークレット情報が無ければ、以下のコードでシークレット情報を生成するよう設定した。起動後にシークレット情報を多要素認証アプリに食わせることで簡単にOTPを実装することができた。

key, err := totp.Generate(totp.GenerateOpts{
	Issuer:      "92thunder.dev",
	AccountName: "r.kunisada661@gmail.com",
})
if err != nil {
	log.Fatal(err)
}
SaveSecret(key.Secret(), key.AccountName(), key.URL())

サインイン時に発行されるsession_idを使って認証後のAPIを使えるか判定するよう実装した。

Echo

EchoはSinatraとかExpressのような、シンプルなWebフレームワークだった。個人的には慣れない言語でjsonからのデータバインディングしたくないと思ってたのでそれがあるだけで十分な機能だった。

// CORSの設定
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
	AllowOrigins: []string{"http://localhost:3000"},
	AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete},
})

// 保存リクエスト
func savePost(c echo.Context) error {
	p := new(Post)
	if err := c.Bind(p); err != nil {
		return err
	}
	post, err := SavePost(p)
	if err != nil {
		return c.JSON(http.StatusBadRequest, err)
	}
	return c.JSON(http.StatusOK, post)
}

nginxの設定

nginxの設定はVPSを使った自前構成にしてから一番学びがある。

# /etc/nginx/sites-available/default
server {
  # _ を含むヘッダーがある場合に必要
  ignore_invalid_headers off;

  # 前方一致にしておかないと正規表現で記述していたnext.js用の設定が勝ってしまっていた
  location ^~ /api/ {
    # 末尾に / がないと、 http://127.0.0.1:1323/api にプロキシしてしまう
    proxy_pass http://127.0.0.1:1323/;
    # これが無いとheaderが削られてしまう
    proxy_set_header Host $host;
  }
}

SystemdでGo APIを起動する

Go APIはデーモン化して起動する必要があるのでSystemdを使って起動するよう設定した。このあたりはISUCONの勉強で学んだことを活かせた!

# /etc/systemd/system/blog-api.service
[Unit]
Description = blog-api

[Service]
User = blog
Type = simple
ExecStart = /home/blog/blog/backend/main
WorkingDirectory = /home/blog/blog/backend
Restart = always

[Install]
WantedBy = multi-user.target
# systemctlに追加したserviceファイルを認識させる
systemctl daemon-reload

# マシンが再起動しても自動実行させる
sudo systemctl enable blog-api

# serviceを開始する
sudo systemctl start blog-api

# ステータス確認
systemctl status blog-api -l

(´-`)「正月休み+3連休でブログ一通り動くところまで完成できたので良い1年の始まりだなぁ」