Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
As we all know, Go is a famous programming language and Gin is a high-performance HTTP web framework written in Golang (Go). Gin allows you to build web applications and microservices in Go. It contains a set of commonly used functionalities (e.g., routing, middleware support, rendering, etc.) that reduce boilerplate code and make it simpler to build web applications.
In this blog, we will learn about the better validation errors in Go Gin. We will see how we can retrieve errors from Validator and port from Validator v8 to v9, and in the end, we will see how we can compose a validation message.
Retrieving errors from Validator
As we know that the errors provided by the validation library used by Go Gin are not that great. Gin internally uses httprouter, but it also uses go-playground/validator to validate incoming requests. The validator uses a struct tag to determine what to check and how to validate the struct field.
After sending a request to http://localhost:8080/codingninjas,
Output:
Porting Errors from the validator.v8 to v9
If you have formatted your main.go file, you must have noticed the new import of validator.v8, which is the old version of the Validator. But this is the default validator of Gin. However, the latest version of Gin is v9. If we want to upgrade to validator.v9, we must create our Validator and assign it to binding.validator
2. Now make another file named v8_to_v9.go, now copy this code to this file,
package main
import (
"reflect"
"sync"
"github.com/gin-gonic/gin/binding"
"gopkg.in/go-playground/validator.v9"
)
type defaultValidator struct {
once sync.Once
validate *validator.Validate
}
var _ binding.StructValidator = &defaultValidator{}
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
if kindOfData(obj) == reflect.Struct {
v.lazyinit()
if err := v.validate.Struct(obj); err != nil {
return error(err)
}
}
return nil
}
func (v *defaultValidator) Engine() interface{} {
v.lazyinit()
return v.validate
}
func (v *defaultValidator) lazyinit() {
v.once.Do(func() {
v.validate = validator.New()
v.validate.SetTagName("binding")
// add any custom validations etc. here
})
}
func kindOfData(data interface{}) reflect.Kind {
value := reflect.ValueOf(data)
valueType := value.Kind()
if valueType == reflect.Ptr {
valueType = value.Elem().Kind()
}
return valueType
}
3. After this to run just type
go run main.go v8_to_v9.go
After sending a request to http://localhost:8080/codingninjas
Output:
Composing the validation messages
The validator.feldError interface contains a number of functions that can be used to compose any error message if we wrap the validator.FieldError in our own fieldError struct, then we can get our own custom validation message:
1. Make a new file named fielderror.go and copy this code in that file
package main
import (
"fmt"
"strings"
"gopkg.in/go-playground/validator.v9"
)
type fieldError struct {
err validator.FieldError
}
func (q fieldError) String() string {
var sb strings.Builder
sb.WriteString("validation failed on the field '" + q.err.Field() + "', condition: " + q.err.ActualTag())
if q.err.Param() != "" {
sb.WriteString(" { " + q.err.Param() + " }")
}
if q.err.Value() != nil && q.err.Value() != "" {
sb.WriteString(fmt.Sprintf(", actual: %v", q.err.Value()))
}
return sb.String()
}
2. Now update the main.go file with this code:
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"gopkg.in/go-playground/validator.v9"
)
func main() {
binding.Validator = new(defaultValidator)
r := gin.Default()
r.GET("/codingninjas", func(c *gin.Context) {
var query struct {
Ninja string `form:"ninja" json:"ninja" binding:"required"`
}
if err := c.ShouldBind(&query); err != nil {
for _, fieldErr := range err.(validator.ValidationErrors) {
c.JSON(http.StatusBadRequest, fmt.Sprint(fieldErr))
return // exit on the first error
}
}
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})
r.Run()
}
3. After the above step, run the following command in the terminal
Goroutines are procedures or functions that operate parallel to other procedures or components. Goroutines can be compared to thin threads. When compared to the cost of a line, a goroutine is extremely inexpensive. Go applications frequently have thousands of Goroutines running at once.
Can we declare multiple variables at once in Go?
Yes, we can declare multiple variables at once in Go.
var v1, v2, ... type
Which keyword is used to import the packages in Go language?
The import keyword is used to import packages into our Go language program, as well as to import packages into other packages.
What is the GOPATH environment variable in go programming?
The GOPATH environment variable basically specifies the location of the workspace. You must have to set this environment variable while developing Go code.
Conclusion
In this blog, we have learned about the better validation errors in Go Gin. We have seen how we can retrieve errors from Validator and port from Validator v8 to v9, and in the end, we saw how we could compose a validation message.