Golangのechoとvalidator.v9を使って、独自のバリデータタグを定義できるまでの手順の紹介.
echoでカスタムバリデータを扱う
公式ページを参考にしつつ、echo.Validatorにカスタムバリデータを設定する.
まずはカスタムバリデータを作成する.
// CustomValidator
type CustomValidator struct {
validator *validator.Validate
}
// NewValidator
func NewValidator() echo.Validator {
return &CustomValidator{validator: validator.New()}
}
// Validate validate
func (cv *CustomValidator) Validate(i interface{}) error {
return cv.validator.Struct(i)
}
作成したバリデータをe.Validatorに設定.
func main() {
e := echo.New()
e.Validator = NewValidator()
e.GET("/", func(c echo.Context) (err error) {
u := new(User)
if err = c.Bind(u); err != nil {
return
}
if err = c.Validate(u); err != nil {
return
}
return c.JSON(http.StatusOK, u)
})
e.Logger.Fatal(e.Start(":1323"))
}
これでvalidator.v9が使えるようになった.
バリデーションを実施する
validator.v9でバリデーションを実施してみる.
例えばFooStruct
を定義して、validate
項目にrequied
タグを設定すると必須になる.
他にも色々なタグがあって便利なので、公式ページをみて自分の用途にあったバリデーションを設定して使う.
// Foo struct
type Foo struct {
Bar string `query:"bar" validate:"requied"`
}
func main() {
e := echo.New()
e.Validator = NewValidator()
e.GET("/", func(c echo.Context) (err error) {
u := new(Foo)
if err = c.Bind(u); err != nil {
rreturn echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if err = c.Validate(u); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.(validator.ValidationErrors).Error())
}
return c.JSON(http.StatusOK, u)
})
e.Logger.Fatal(e.Start(":1323"))
}
これでrequied
バリデーションが設定され,クエリパラメータにbar項目を含めないとバリデーションに失敗するようになった.
$ curl -X GET "http://127.0.0.1:1322"
{"message":"Key: 'Foo.Bar' Error:Field validation for 'Bar' failed on the 'required' tag"}
$ curl -X GET "http://127.0.0.1:1322/?bar=hoge"
{"Bar":"hoge"}
独自のカスタムバリデーションを定義する
独自のバリデーションタグを作成したい場合は、 validator.RegisterValidation()
を利用する.
validator.RegisterValidation()
を設定するためにまずはboolを返すメソッドを定義する.
以下は文字列がhogehoge
と一致しない場合に失敗するバリデーションの例.ここで好きに条件を定義できる.
// CustomValidate
func CustomValidate(fl validator.FieldLevel) bool {
return fl.Field().String() == "hogehoge"
}
バリデーションが作成できたのでカスタムバリデータにCustomValidate()
を追加する.
// CustomValidator
type CustomValidator struct {
validator *validator.Validate
}
// NewValidator
func NewValidator() echo.Validator {
return &CustomValidator{validator: validator.New()}
}
// Validate validate
func (cv *CustomValidator) Validate(i interface{}) error {
cv.validator.RegisterValidation("hogehoge", CustomValidate)
return cv.validator.Struct(i)
}
これで新たにhogehoge
バリデーションタグを作ることができた.
先ほど定義したFoo Struct
にルールを追加する.
// Foo struct
type Foo struct {
Bar string `query:"bar" validate:"requied,hogehoge"`
}
これでhogehoge
ルールが追加され、独自タグでのバリデーションが行えるようになった.
今までのrequired
も動作している.
$ curl -X GET "http://127.0.0.1:1322/?bar=hoge"
{"message":"Key: 'Foo.Bar' Error:Field validation for 'Bar' failed on the 'hogehoge' tag"}
$ curl -X GET "http://127.0.0.1:1322"
{"message":"Key: 'Foo.Bar' Error:Field validation for 'Bar' failed on the 'required' tag"}
$ curl -X GET "http://127.0.0.1:1322/?bar=hogehoge"
{"Bar":"hogehoge"}
こんな感じでechoとvalidator.v9を利用して、簡単にバリデーションが実施できる.
validator.v9はデフォルト状態でも簡単なアプリには必要十分なバリデーションが揃っているし、紹介した以外にも色々設定できることもあるようなのでどんどん使っていきたい.
全体コード
最終的なコードはこんな感じでした.
package main
import (
"net/http"
"github.com/labstack/echo"
"gopkg.in/go-playground/validator.v9"
)
// CustomValidator
type CustomValidator struct {
validator *validator.Validate
}
// NewValidator
func NewValidator() echo.Validator {
return &CustomValidator{validator: validator.New()}
}
// Validate validate
func (cv *CustomValidator) Validate(i interface{}) error {
cv.validator.RegisterValidation("hogehoge", CustomValidate)
return cv.validator.Struct(i)
}
// CustomValidate
func CustomValidate(fl validator.FieldLevel) bool {
return fl.Field().String() == "hogehoge"
}
// Foo struct
type Foo struct {
Bar string `query:"bar" validate:"required,hogehoge"`
}
func main() {
e := echo.New()
e.Validator = NewValidator()
e.GET("/", func(c echo.Context) (err error) {
u := new(Foo)
if err = c.Bind(u); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if err = c.Validate(u); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.(validator.ValidationErrors).Error())
}
return c.JSON(http.StatusOK, u)
})
e.Logger.Fatal(e.Start(":1322"))
}