
Implement data validation in Go
Data validation is an important part of software development. It makes sure that input data is accurate and meets the requirements before processing or storing it. In Go, data validation is simple and flexible.
This guide will teach you how to use struct tags to validate data and make your apps safe and reliable. From creating validation logic to using built-in validation tags.
Prerequisites
- Go 1.21
 
Setup project
Setting up the Go project dependencies.
go mod init app
go get github.com/gin-gonic/ginProject structure
├─ main.go
├─ models
│  └─ user.go
└─ public
   └─ index.htmlProject files
user.go
The User struct is designed for testing validation within the application, incorporating validation tags to enforce specific rules.
package models
type User struct {
	Id        int    `binding:"required" msg:"Required"`
	Name      string `binding:"max=10" msg:"Maximum length is 10"`
	Email     string `binding:"email" msg:"Invalid email address"`
	Age       int    `binding:"min=1,max=100" msg:"Must between 1 and 100"`
	BirthDate string `binding:"datetime=01/02/2006" msg:"Invalid date format"`
}Since the default error messages are not user-friendly, we added a custom msg tag to define more meaningful error messages.
main.go
This file is the main entry point for our application. It will create and set up the minimal Go web application.
package main
import (
	"app/models"
	"net/http"
	"reflect"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
)
func main() {
	router := gin.Default()
	router.LoadHTMLFiles("public/index.html")
	router.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})
	router.POST("/", func(c *gin.Context) {
		var user models.User
		if err := c.ShouldBind(&user); err != nil {
			c.HTML(http.StatusOK, "index.html", gin.H{"User": user, "Errors": getErrors(err, user)})
			return
		}
		c.HTML(http.StatusOK, "index.html", gin.H{"Pass": true, "User": user})
	})
	router.Run()
}
func getErrors(err error, obj any) map[string]string {
	messages := getMessages(obj)
	errors := map[string]string{}
	for _, e := range err.(validator.ValidationErrors) {
		errors[e.Field()] = messages[e.Field()]
	}
	return errors
}
func getMessages(obj any) map[string]string {
	t := reflect.TypeOf(obj)
	messages := map[string]string{}
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		messages[field.Name] = field.Tag.Get("msg")
	}
	return messages
}GETmethod to return the input form.POSTmethod for form submission and validation of user input.getErrors()returns the error information.getMessages()leverages our custommsgtag to retrieve error messages for specific fields.
index.html
The HTML user input form is designed to test the validation rules applied to the User struct. It typically includes fields that correspond to the properties of the User struct.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css" rel="stylesheet">
    <script>
        function fill(valid) {
            document.getElementById('id').value = (valid ? '1' : '')
            document.getElementById('name').value = (valid ? 'foo' : 'my name is foo')
            document.getElementById('email').value = (valid ? 'foo@mail.com' : 'mail')
            document.getElementById('age').value = (valid ? '10' : '101')
            document.getElementById('birthdate').value = (valid ? '01/01/2000' : '01012000')
        }
    </script>
</head>
<body>
    <div class="container">
        <div class="row mt-3">
            <form method="post">
                <div class="mb-3 col-12">
                    <label class="form-label" for="id">Id</label>
                    <input id="id" name="Id" class="form-control form-control-sm" value="{{.User.Id}}" />
                    {{if .Errors.Id}}<span class="text-danger">{{.Errors.Id}}</span>{{end}}
                </div>
                <div class="mb-3 col-12">
                    <label class="form-label" for="name">Name</label>
                    <input id="name" name="Name" class="form-control form-control-sm" value="{{.User.Name}}" />
                    {{if .Errors.Name}}<span class="text-danger">{{.Errors.Name}}</span>{{end}}
                </div>
                <div class="mb-3 col-12">
                    <label class="form-label" for="email">Email</label>
                    <input id="email" name="Email" class="form-control form-control-sm" value="{{.User.Email}}" />
                    {{if .Errors.Email}}<span class="text-danger">{{.Errors.Email}}</span>{{end}}
                </div>
                <div class="mb-3 col-12">
                    <label class="form-label" for="age">Age</label>
                    <input id="age" name="Age" class="form-control form-control-sm" value="{{.User.Age}}" />
                    {{if .Errors.Age}}<span class="text-danger">{{.Errors.Age}}</span>{{end}}
                </div>
                <div class="mb-3 col-12">
                    <label class="form-label" for="birthdate">Birth Date</label>
                    <input id="birthdate" name="BirthDate" class="form-control form-control-sm"  value="{{.User.BirthDate}}" />
                    {{if .Errors.BirthDate}}<span class="text-danger">{{.Errors.BirthDate}}</span>{{end}}
                </div>
                <div class="col-12">
                    <input type="button" class="btn btn-sm btn-danger" onclick="fill(0)" value="Fill invaid data" />
                    <input type="button" class="btn btn-sm btn-success" onclick="fill(1)" value="Fill vaid data" />
                    <button class="btn btn-sm btn-primary">Submit</button>
                </div>
                {{if .Pass}}
                <div class="alert alert-success mt-3">
                    Validation success!
                </div>
                {{end}}
            </form>
        </div>
    </div>
</body>We use Go's HTML template syntax, such as {{if .Errors.Id}}, to display error messages to the user.
Run project
go run main.goOpen the web browser and goto http://localhost:8080
You will find this test page.

Testing
Click "Fill invalid data" and then click "Submit" to see the error messages displayed in the input form.

Click "Fill valid data" and then "Submit" again. You should see the validation success message displayed in the input form.

Conclusion
This article has covered implementing the basic data validation, helping you build reliable and user-friendly applications. Apply these practices to enhance both the robustness and usability of your Go web application.
Source code: https://github.com/stackpuz/Example-Validation-Go
Create a CRUD Web App in Minutes: https://stackpuz.com



