【Go言語】ginを用いたWebアプリケーション入門
htmlやjsonを返すGo言語のWebアプリの作り方をご紹介したいと思います。
WEBアプリのフレームワークは複数ありますが、代表的なものはginなどです。
フレームワーク名 | スター数 | リンク |
---|---|---|
gin | 55.9k | https://github.com/gin-gonic/gin |
beego | 27.8k | https://github.com/beego/beego |
gokit | 22.4k | https://github.com/go-kit/kit |
eco | 21.7k | https://github.com/labstack/echo |
今回はstarが多いginを利用します。
目次
最小の構成
main.goとgo.modだけでサーバーを起動することができます。
内容 | コマンド |
---|---|
go.mod作成 | go mod init 任意のプロジェクト名 |
ginインストール | go get github.com/gin-gonic/gin |
起動コマンドはいつも通りのgo run main.go
もしくはgo run .
です。
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { // Engineインスタンスを生成する r := gin.Default() // エンドポイントと処理を結び付ける r.GET("/ping", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "pong"}) }) // 起動時のポート番号を指定する r.Run(":8080") }
動作確認
このファイルを追加し起動させている間にhttp://localhost:8080/ping
にアクセスすると、{"message": "pong"}
が返ってきます。
ブラウザのバーに上記のURLをコピペすれば、動作を確認できます。
エンドポイントの増やし方
先程はGETメソッドのpingパスの処理のみを定義しました。
この章では、エンドポイントの増やし方をご紹介します。
メソッドの種類
r.POST("/ping", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "pong"}) })
どのメソッドであってもr.メソッド名
で指定をします。
- GET
- POST
- PUT
- DELETE
パスの指定
/ping
のようにスラッシュ始まりで記述します。
パスパラメータを利用する場合は、/ping/:id/:name
のように:パラメータ名
形式で指定します。
この例の様に複数のパスパラメータを利用することもできます。
/ping/30/taro
にアクセスしたとすると、idに"30"、nameに"taro"が入ります。
処理で各種パラメータを利用する
以下の3つのパラメータを取得する方法を説明いたします。
クエリパラメータ パスパラメータ フォームパラメータ
加えて、リクエスト情報全体の取得方法も書いています。
クエリパラメータ
r.GET("/ping", func(c *gin.Context) { id := c.Query("id") c.JSON(http.StatusOK, gin.H{"message": id}) })
パスが/ping?id=30&name=taro
だとすると「?」以降がクエリパラメータです。
このパスにリクエストが来た場合、r.GETの第2引数に渡した関数が実行されます。
クエリパラメータの名前指定はパスパラメータとは違い、/ping
のパス部分に含める必要はありません。
取得はQueryメソッドで行います。
このコード例で/ping?id=30
にリクエストが来ると、idにstring型の"30"が入ります。
パスパラメータ
r.GET("/ping/:id", func(c *gin.Context) { id := c.Param("id") c.JSON(http.StatusOK, gin.H{"message": id}) })
取得はParamメソッドで行います。
パスパラメータを利用する場合は、/:パラメータ名
をエンドポイントのパスに含める必要があります。
フォームパラメータ
r.POST("/ping", func(c *gin.Context) { id := c.PostForm("id") c.JSON(http.StatusOK, gin.H{"message": id}) })
取得はPostFormメソッドで行います。
これはあまり使わないと思います。
リクエスト情報を取得する
r.POST("/ping", func(c *gin.Context) { request := c.Request() c.JSON(http.StatusOK, gin.H{"message": request.URL.String()}) })
gin.Context型の変数から、 http.Request型の変数を取得できます。
RequestからボディやURLなど全ての情報を持ってくることができます。
フォームパラメータを複数取得する場合などは、こちらを使いましょう。
request.Bodyとすればボディを取得できますが、これはstring型ではなくio.ReadCloser型なので注意が必要です。
string型にするには以下のように書きます。
// body は[]byte型 body, _ := io.Readall(c.Request().Body) s := string(body)
レスポンスの設定
レスポンスを定義しているのは以下の部分です。
c.JSON(http.StatusOK, gin.H{"message": request.URL.String()})
})
c.メソッド名で記述していて、他にもメソッドがいくつかあります。
主に使いそうなのは下の3つです。
JSON String HTML
Stringはc.String(http.StatusOK, "hoge")
のように書きます。
HTMLを利用する場合には、htmlファイルを作成しておき、事前にHTMLを読み込む関数を呼ぶ必要があります。
// templatesディレクトリ配下のhtmlを読み込む r.LoadHTMLGlob("templates/*") r.GET("/ping", func(c *gin.Context) { c.HTML(http.StatusOK, "ping.html", gin.H{ "message": "pong", }) })
c.HTMLメソッドの第2引数では、htmlファイル名を渡します。読み込んだディレクトリパスに指定したファイルが存在しなければ、レスポンスでHTMLを返せません。
第3引数gin.H{~}
では、htmlに埋め込む値を記述しています。なので埋め込む値が無ければ、gin.H{}内の中身は無くても大丈夫です。
各処理に共通の値を渡す
type Config struct{ Message string // 色々入れる } func main() { r := gin.Default() // 実際はconst定数や環境変数に設定した値を入れる config := Config{} // 関数の外の変数configを、変数内で利用できる r.GET("/ping", func(c *gin.Context) { m := config.Message c.JSON(http.StatusOK, gin.H{"message": m}) }) router.Run(":8080") }