# 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":"文字だ"}