背景
Ginでバックエンド開発をしている際に、GinをCloud Run functionsでエンドポイントごとに関数をデプロイしたかったものの、公式ドキュメントを含め掲載されていなかったため、備忘録として執筆しました。
方法
早速ですがコードの方を見ていきます。
ディレクトリ構成
#ディレクトリ構成
arumonogohan-app git:(main) ✗ tree
.
├── app.yaml #GCP設定用ファイル
├── cmd
│ └── main.go #ローカル開発用
├── gcp_functions.go #GCP
├── go.mod
└── go.sum
go.mod
,go.sum
と同じルート階層にデプロイするためのファイルを作成します。
//gcp_functions.go (ファイル名は任意)
package gcp //パッケージ名も任意
import (
"net/http"
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
"github.com/gin-gonic/gin"
"github.com/kikudesuyo/arumonogohan-app/api/handler"
)
func init() {
functions.HTTP("LinbotCallback", func(w http.ResponseWriter, req *http.Request) {
// Ginのルーターを作成
r := gin.Default()
// Ginのハンドラを定義
r.POST("/callback", handler.HandleLinebotCallback)
// リクエストをGinに渡して処理させる
r.ServeHTTP(w, req)
})
}
GCPにデプロイする際にはinit関数を探して、その中に記載されているエンドポイントをデプロイします。
また、functions-framework-go/functions
のfunctions.HTTPの引数は以下のようになります。
//functions.HTTPメソッド
func functions.HTTP(name string, fn func(http.ResponseWriter, *http.Request))
HTTP registers an HTTP function that becomes the function handler served at "/" when environment variable `FUNCTION_TARGET=name`
このことから第一引数には関数の名前、第二引数には(http.ResponseWriter, *http.Request)型の関数を用意する必要があります。
しかし、既にGinのアプリケーションで開発されたハンドラの引数は、
func HandleLinebotCallback(c *gin.Context)
となっており、型の違いによるエラーが発生してしまします。
そのため、http
からGin
へキャストすることで、解決出来ます。
さいごに
GCPのCloud Run functionsでGinのアプリケーションをデプロイすることが出来ました。ローカルの環境とクラウドの環境が変わってしまいコードが汚くなってしまいがちでしたが、うまくローカルとクラウドの棲み分けをすることが出来たためクラウドに依存することなく実装することが出来ました。Vercelにデプロイしたときはディレクト
リ構成が非常に汚くなってしまったのでGCPに感動しています。
ローカル環境とクラウドとの環境の差異が小さいため、学習コストが低く、初心者が最初にデプロイするのにピッタリだと思いました。
また、今回の発見により、「コードの品質を保つ」+「学習コストが低い」+「サーバーレスで費用が小さい」という最高の3要素を実現出来たため非常に満足しています。是非参考にしてみてください。