こんにちは。KOUKIです。
とある企業でWebプログラマーとして働いています。
Go言語で開発しており、そのフレームワークであるGinに触る機会が多いです。
本記事では、Ginのカスタムミドルウェアの作成方法について紹介します。
<目次>
事前準備
開発に必要なファイルを用意します。
1 2 |
touch main.go go mod init test |
作成したmain.goファイルに、以下のWebサーバーコードを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package main import ( "fmt" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { fmt.Println("########### DO PING ############") c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() } |
「go run main.go」にてWebサーバーを立ち上げ、「localhost:8080/ping」へブラウザからアクセスすると、以下のログ出力が確認できると思います。
1 |
########### DO PING ############ |
カスタムミドルウェアの実装方法
ソフトウェアの世界では、ミドルウェアは様々な意味を持ちます。
しかし、この記事では、HTTPのリクエストの受信からハンドラーが実行結果をリクエストに乗せて返すまでの中間(ミドル)で任意の処理をするものと定義します。
Ginでは、カスタムミドルウェアを簡単に実装することができます。
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 |
package main import ( "fmt" "github.com/gin-gonic/gin" ) // カスタムミドルウェア func MyCustomLogger() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("-------MyCustomLogger Start------") // pingハンドラ内の処理に移行 c.Next() fmt.Println("-------MyCustomLogger End------") } } func main() { r := gin.Default() r.Use(MyCustomLogger()) r.GET("/ping", func(c *gin.Context) { fmt.Println("########### DO PING ############") c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() } |
gin.HandlerFuncを戻り値に持つMyCustomLoggerを定義しました。これをmain関数内で読み込みます。
ミドルウェアを読み込む方法方は、大きく分けて2つあります。
1 2 3 4 5 6 7 8 9 10 |
# 方法1. ginのデフォルトのエンジンを使う r := gin.Default() r.Use(MyCustomLogger()) # 方法2. ginをNewする r := gin.New() r.Use(MyCustomLogger()) # 以下のようにすると複数読み込める r.Use(MyCustomLogger1(),MyCustomLogger2(),MyCustomLogger3()) |
方法1は、Ginにデフォルトで組み込まれているミドルウェアに相乗りする形でカスタムミドルウェアを有効にします。
一方、方法2は、ミドルウェアの実行をカスタムミドルウェアのみに限定したい場合に用います。
Webサーバーを立ち上げ直して、「http://localhost:8080/ping」にアクセスしてみましょう。
1 2 3 4 5 6 7 8 9 |
# Ctrl + cでプログラムを停止 # サーバーを立ち上げ直す go run main.go # localhost:8080/pingにアクセス -------MyCustomLogger Start------ ########### DO PING ############ -------MyCustomLogger End------ |
ログの出力結果からカスタムミドルウェアが有効になっていることがわかりますね。
しかも、便利なことに「c.Next()」を使うと実行する処理を切り替えることができます。今回の場合は、MyCustomLoggerがStartログを出力した後、pingハンドラーに処理を切り替え、その後、再びMyCustomLoggerに戻りEndログを出力しました。
カスタムミドルウェアの値の受け渡し
カスタムミドルウェアは、ginのコンテキスト(*gin.Context)を持っているので、値の受け渡しが可能です。
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 |
package main import ( "fmt" "github.com/gin-gonic/gin" ) func MyCustomLogger() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("-------MyCustomLogger Start------") // データをセット c.Set("v", 123) // ハンドラを内の処理に移行 c.Next() fmt.Println("-------MyCustomLogger End------") } } func main() { r := gin.Default() // r.Use(MyCustomMiddleWare()) r.Use(MyCustomLogger()) r.GET("/ping", func(c *gin.Context) { fmt.Println("########### DO PING ############") // データを受け取る fmt.Println(c.Get("v")) c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() } |
上記では、データをセットするために「c.Set(“v”, 123)」、データを取得するために「c.Get(“v”)」を使っています。この値は、Key-Valueのペアで格納されます。
先ほどと同じ要領で、動作確認をしましょう。
1 2 3 4 5 6 7 8 9 10 |
# Ctrl + cでプログラムを停止 # サーバーを立ち上げ直す go run main.go # localhost:8080/pingにアクセス -------MyCustomLogger Start------ ########### DO PING ############ 123 true -------MyCustomLogger End------ |
「123 true」と取得できましたね。Getメソッドは、セットした値と取得結果を返してくれます。
カスタムミドルウェアの実行順番
最後に、カスタムミドルウェアの実行順番を確認してみましょう。
実験のため、もう一つカスタムミドルウェアを用意します。
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 |
package main import ( "fmt" "github.com/gin-gonic/gin" ) func MyCustomMiddleWare() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("-------MyCustomMiddleWare Start------") c.Next() fmt.Println("-------MyCustomMiddleWare End------") } } func MyCustomLogger() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("-------MyCustomLogger Start------") // データをセット c.Set("v", 123) // ハンドラを内の処理に移行 c.Next() fmt.Println("-------MyCustomLogger End------") } } func main() { r := gin.Default() r.Use(MyCustomMiddleWare()) r.Use(MyCustomLogger()) r.GET("/ping", func(c *gin.Context) { fmt.Println("########### DO PING ############") // データを受け取る fmt.Println(c.Get("v")) c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() } |
MyCustomMiddleWare関数を作成し、main関数で読み込みました。
このプログラムを実行すると、以下の結果を受け取れました。
1 2 3 4 5 6 7 8 9 10 11 12 |
# Ctrl + cでプログラムを停止 # サーバーを立ち上げ直す go run main.go # localhost:8080/pingにアクセス -------MyCustomMiddleWare Start------ -------MyCustomLogger Start------ ########### DO PING ############ 123 true -------MyCustomLogger End------ -------MyCustomMiddleWare End------ |
MyCustomMiddleware —-Next()—->MyCustomLogger —-Next()—->Ping Handler—> MyCustomLogger —> MyCustomMiddlewareの順番でデータが流れていますね。
どうやらミドルウェアは、適用した順番で実行されるようですね。
1 2 |
r.Use(MyCustomMiddleWare()) r.Use(MyCustomLogger()) |
おわりに
個人的にカスタムミドルウェアの作成は意外に面白いと思いましたが、いかがでしたでしょうか。
カスタムミドルウェアを上手に使うと、必ず実行したい前処理、後処理がかけて便利ですよね。
アプリケーション開発に幅を持たせてくれそうです^^
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。