フレームワーク「GIN」を使ってみた（バリデーション処理）

#修正
#バリデーション方法

[フレームワーク「GIN」を使ってみた（CRUD処理）](https://qiita.com/koshi_an/items/2e44a66e516c382e1ee7) を改造して、バリデーションを追加します。

今回は、[gopkg.in/go-playground/validator.v9](https://github.com/go-playground/validator) を利用します。

#修正内容

以下のソースを追加します。

```go:form/users.go
package forms

import (
	"regexp"

	"gopkg.in/go-playground/validator.v9"
)

type Users struct {
	Id     int
	UserId string `validate:"required,min=5,max=25,alphanum"` // 必須、5～25文字、半角英数
	Name   string `validate:"required,is_tarou"`              // 必須、カスタムバリデーション
}

// tarou はオリジナルバリデーション
func tarou(fl validator.FieldLevel) bool { //引数の型、返り値は固定
	name := fl.Field().String()
	tarou := regexp.MustCompile(`太郎`)
	// name に太郎を含まないとエラーとする
	return tarou.MatchString(name)
}

// バリデーションチェックを行って、結果とNGの場合にエラーメッセージ群を返す
func (form *Users) Validate() (ok bool, result map[string]string) {
	result = make(map[string]string)
	// 構造体のデータをタグで定義した検証方法でチェック
	// err := validator.New().Struct(*form)
	validate := validator.New()
	validate.RegisterValidation("is_tarou", tarou) //第一引数をvalidateタグで設定した名前に合わせる
	err := validate.Struct(*form)
	if err != nil {
		errors := err.(validator.ValidationErrors)
		if len(errors) != 0 {
			for i := range errors {
				// フィールドごとに、検証
				switch errors[i].StructField() {
				case "UserId":
					switch errors[i].Tag() {
					case "required", "min", "max", "alphanum":
						result["UserId"] = "5文字以上25文字以下の半角英数値で入力してください"
					}
				case "Name":
					switch errors[i].Tag() {
					case "required":
						result["Name"] = "名前を入力してください"
					case "is_tarou":
						result["Name"] = "名前には、太郎を利用してください"
					}
				}
			}
		}
		return false, result
	}
	return true, result
}
```

上記、バリデーションを登録処理のみ対応します。
修正箇所のみ記載します。

```go:routes/users_controller.go

func Create(c *gin.Context) {
	log.Print("登録処理")
	DbConnection, _ := sql.Open("sqlite3", "./db/sqlite3/test.db") // main.goからのパスを指定
	defer DbConnection.Close()

	userid := c.PostForm("userID")
	name := c.PostForm("name")

	// 処理を追加
	form := forms.Users{
		UserId: userid,
		Name:   name,
	}

	log.Print("UserId : ", form.UserId)
	log.Print("Name : ", form.Name)
	// バリデーションの検証を行う
	if ok, errorMessages := form.Validate(); !ok {
		log.Print("入力エラーあり")
		log.Print(errorMessages)
		// ステータスコード：400を返す。（正しいかは分からない)
		c.HTML(http.StatusBadRequest, "new", gin.H{"User": form, "errorMessages": errorMessages})
		c.Abort()
	}
	// 処理を追加

	cmd := "INSERT INTO m_users (user_id, name) VALUES (?, ?)"
	_, err := DbConnection.Exec(cmd, userid, name)
	if err != nil {
		log.Fatalln(err)
	}
	c.Redirect(http.StatusMovedPermanently, "/user")

}
```

画面にもエラーメッセージの表示箇所を追加します。

```html:templates/new.html
{{define "new"}}
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>新規登録</title>
</head>
<body>
    <form action="/user/new" method="POST">
        user_id:<input type="text" name="userID" value="{{.User.UserId}}"> {{.errorMessages.UserId}}
        <br>
        name: <input type="text" name="name" value="{{.User.Name}}"> {{.errorMessages.Name}}
        <br>
        <input type="submit" value="登録">
  </form>
</body>
</html>
{{end}}
```


#参考サイト
[go-playground/validator リクエストパラメータ向けValidationパターンまとめ](https://qiita.com/RunEagler/items/ad79fc860c3689797ccc)
[golang　バリデート（validator.v9）](https://qiita.com/quicksort/items/c68b96009a495b22ded9)
[Golangでバリデーションチェックを行う](https://kikki.hatenablog.com/entry/2018/10/28/115246)
[公式ドキュメント](https://godoc.org/gopkg.in/go-playground/validator.v9)