Ginでカスタムバリデーションを実装してみた。

全般

こんにちわ!相も変わらずGolangが大好きな私、佐々木です!

今日はGolangのフレームワーク、 Ginを使っている中で独自のバリデータを作るのがとても簡単だったのでご紹介します。

Gin

GinはGolangのWebフレームワークで、同じくGolangのWebフレームワーク「Martini」にインスパイアされた非常に高パフォーマンスかつ、人気のフレームワークです。
また、GithubStarも数あるGolangのWebフレームワークの中で最多となっています。

少し前のリストですが、順位の変動はなさそうです。

GitHub - mingrammer/go-web-framework-stars: Web frameworks for Go, most starred on GitHub
:star: Web frameworks for Go, most starred on GitHub - GitHub - mingrammer/go-web-framework-stars: Web frameworks for Go, most starred on GitHub

デフォルトバリデーター

Ginでは、デフォルトのバリデーターとしてhttps://github.com/go-playground/validatorを使用しています。一例としてですが、バリデーターを適用させる際に、入力される最小値を1とするなら以下のように書きますね。(binding:”required,min=1″)

type transferRequest struct {
	FromAccountID int64  `json:"from_account_id" binding:"required,min=1"`
	......
}

独自項目などでバリデーターを書くのであれば以下のような書き方も可能です。
こちらは貨幣の略称をバリデーターにかけたものです。(binding:”required,oneof=USD EUR JPY”)

type createAccountRequest struct {
        ......
	Currency string `json:"currency" binding:"required,oneof=USD EUR JPY"`
}

これでもやりたいことは出来ますが、対象項目が10、20と多くなれば、このような書き方はあんまりしたくないですね。。。

カスタムバリデーター

ということで、カスタムバリデーターを調べたらこちらに作成方法がありました。

examples/server.go at master · gin-gonic/examples
A repository to host examples and tutorials for Gin. - examples/server.go at master · gin-gonic/examples

この内容を参考に作成してみます。

API部分をちょっと雑でしたが書いてみました。こちらの7行目に記載している、
「v.RegisterValidation(“currency”, validCurrency)」の第一引数にはバリデーションとして使用するタグ名、第二引数は関数を記載します。

(”github.com/go-playground/validator/v10″のimport文では末尾の“v10”を忘れずに記載します。)

import (
	......
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
)

type Server struct {
func NewServer(store db.Store) *Server {
	server := &Server{store: store}
	router := gin.Default()

	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		v.RegisterValidation("currency", validCurrency)
	}

	router.GET("/transfers/:id", server.getTransfer)
	router.POST("/transfers", server.createTransfer)

	server.router = router
	return server
}

第二引数の関数部分へtrue or falseで返せるように実装します。

var listCurrencies = map[string]bool{
	"USD": true,
	"EUR": true,
	"JPY": true,
}

var validCurrency validator.Func = func(fieldLevel validator.FieldLevel) bool {
	if currency, ok := fieldLevel.Field().Interface().(string); ok {
		return listCurrencies[currency]
	}
	return false
}

ロジックについては完了です。

最後にバリデーターを以下のように記載します。(binding:”required,currency”)
前述のAPI部分で触れた、バリデーターとして使用するタグ名はここで使用します。

type createAccountRequest struct {
        ......
	Currency string `json:"currency" binding:"required,currency"`
}

最後に

今回はGinについて触れましたが、Golangといえば、「net/http」ですよね。

今後はnet/httpについて触れていきたいなと思います。

では、また!

コメント