# ginでフォーム、JSONのリクエストを受け取る
Go言語はじめたでMacにGoが動く環境を作ったので、今日はGoのwebフレームワークであるgin (opens new window)をさわる。
フォーム、JSONのリクエストから取得できる値をたしかめていく。
# ginをインストールして動かす
まずはgin
のインストールから始める。
go mod init
でモジュールの初期化をする。
$ go mod init github.com/nansystem/gin-sample
main.go
を作成し、go run
でwebサーバーをたちあげる。
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run()
}
$ go run main.go
curl
でアクセスすると、JSONでレスポンスが返ってきた。
これでgin
の起動確認ができた。
$ curl http://localhost:8080/ping \
-H 'Content-Type:application/json'
{"message":"pong"}
# URLクエリ文字列の取得
c.Query
でURLクエリ文字列を取得できる。取得できる値の型はstring
である。
c.DefaultQuery
の第二引数でデフォルト値を設定できる。
r.GET("/get", func(c *gin.Context) {
s := c.Query("str")
n := c.Query("num")
b := c.Query("bool")
l := c.DefaultQuery("limit", "10")
message := fmt.Sprintf("s: %v, n: %v, b: %v, l: %v", s, n, b, l)
c.String(http.StatusOK, message)
})
curl
のオプション--get
で後続の値をクエリ文字列とし、--data-urlencode
でURLエンコーディングしてリクエストする。
GET /get?str=%E6%96%87%E5%AD%97%E5%88%97&num=123&bool=true HTTP/1.1
$ curl http://localhost:8080/get \
--get \
--data-urlencode 'str=文字列' \
--data-urlencode 'num=123' \
--data-urlencode 'bool=true'
s: 文字列, n: 123, b: true, l: 10
# URLパスの取得
:name
のようにコロンに続けてパス名を指定することでc.Param("name")
で値を取得する。
*action
のようにアスタリスクに続けてパス名を指定すると、c.Param("action")
で残りの全てのパスを取得する。
r.GET("/path/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
message := name + " is " + action
c.String(http.StatusOK, message)
})
$ curl http://localhost:8080/path/hoge/fuga/piyo/
hoge is /fuga/piyo/
# フォームのPOST
c.PostForm
でフォームの値を取得できる。取得できる値の型はstring
である。
c.DefaultPostForm
の第二引数でデフォルト値を設定できる。
r.POST("/post", func(c *gin.Context) {
s := c.PostForm("str")
n := c.PostForm("num")
b := c.PostForm("bool")
l := c.DefaultPostForm("limit", "10")
message := fmt.Sprintf("s: %v, n: %v, b: %v, l: %v", s, n, b, l)
c.String(http.StatusOK, message)
})
$ curl -X POST http://localhost:8080/post \
--data-urlencode 'str=文字列P' \
--data-urlencode 'num=1234' \
--data-urlencode 'bool=false' \
--data-urlencode 'limit=20'
s: 文字列P, n: 1234, b: false, l: 20
# JSONのPOST
struct
を用意する。
type JsonRequest struct {
FieldStr string `json:"field_str"`
FieldInt int `json:"field_int"`
FieldBool bool `json:"field_bool"`
}
JSONからstruct
へ値をマッピングするのはBindJSON
かShouldBindJSON
関数のいずれかを使う。
BindJSON
はHTTPステータスを400にして、Content-Typeヘッダーをtext/plain
にするようだ。
application/json
でレスポンスを返したいから、ShouldBindJSON
を使う。
gin.H
はmap[string]interface{}
のショートカット。
This sets the response status code to 400 and the Content-Type header is set to text/plain; charset=utf-8. https://github.com/gin-gonic/gin#model-binding-and-validation (opens new window)
gin.H is a shortcut for map[string]interface{}
https://github.com/gin-gonic/gin#xml-json-yaml-and-protobuf-rendering (opens new window)
r.POST("/postjson", func(c *gin.Context) {
var json JsonRequest
if err := c.ShouldBindJSON(&json); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"str": json.FieldStr, "int": json.FieldInt, "bool": json.FieldBool})
})
空のJSONを渡してもエラーにならない。
$ curl -X POST http://localhost:8080/postjson \
-H 'content-type: application/json' \
-d '{}'
{"bool":false,"int":0,"str":""}
struct
に存在していないフィールドを渡しても無視されてエラーにはならない。
$ curl -X POST http://localhost:8080/postjson \
-H 'content-type: application/json' \
-d '{ "hoge": 1 }'
{"bool":false,"int":0,"str":""}
型が違えばエラーになる。
$ curl -X POST http://localhost:8080/postjson \
-H 'content-type: application/json' \
-d '{ "field_str": 1 }'
{"error":"json: cannot unmarshal number into Go struct field JsonRequest.field_str of type string"}
型があっていればstruct
に値が無事マッピングされる。
$ curl -X POST http://localhost:8080/postjson \
-H 'content-type: application/json' \
-d '{ "field_str": "文字だ", "field_int": 12, "field_bool": true }'
{"bool":true,"int":12,"str":"文字だ"}