Table of contents
1.
Introduction
2.
Gin
3.
Form Validation
4.
Validator
4.1.
Struct Tags #
4.2.
#ERROR
4.3.
#ValidatorError
5.
Gin’s Validator Customization
6.
Frequently Asked Questions
6.1.
What is Golang used for?
6.2.
What is Gin?
6.3.
What is the main advantage of GoLang?
6.4.
In Golang, how big is a pointer?
6.5.
Is Gin a Web server?
7.
Conclusion
Last Updated: Mar 27, 2024
Medium

Validating Forms with Gin

Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Google engineers have introduced a statically typed, compiled programming language most closely modeled after C, known as Go (also known as Golang). It is an open-source general-purpose computer language that is procedural and concurrent.

So, what's new in this article?

Validating Forms with Gin

Today, we'll be looking at Validating Forms with Gin. But wait! What is Gin?

Gin is a web framework written in the Go language. Let's get started then and learn more about Gin.

Gin

Gin is a high-performance yet very powerful HTTP web framework written in Golang (Go). Gin allows you to build web applications in Go. 

gin in go

Gin is not only really easy to use but also has faster performance. It consists of commonly used functionality sets (e.g., routing, rendering, middleware support, etc.) that help to build web applications in a simpler way.

Form Validation

Validating Forms with Gin protects the app from insufficient data. This data might be malicious, but it might just be accidental – like missing a letter from the name, a digit from a phone number, or misformatting an email.

Form Validation

Form validation protects the user from making mistakes or forgetting to fill in a required field. Hence it throws an error in return.

Validator

The validator provides a lot of different format checks. For example, if we wanted to track something, there's a validator. Gin has a built-in framework that supports struct validation to determine what or where to check and how to validate a struct field. Hence, you can configure all the validation scenarios using simple struct tags #. Let’s now discuss the struct tags for Validating Forms with Gin.

Struct Tags #

As stated in its introduction, Gin is using an HTTP router internally, but it's also using go-playground/validator to validate incoming requests. It is not uncommon to find this kind of code when working with Gin:

type dataToBeRequested struct {
    Name  string `json:"name" binding:"required"`
    Email string `json:"email" binding:"required"`
}

func PostRequiredData(p *gin.Context) {
	var d dataToBeRequested

	if err := p.ShouldBind(&d); err != nil {
		p.JSON(http.StatusBadRequest, gin.H{"error": "field validation is failed"})
		return
	}
	
}

In the above example, the struct dataToBeRequested has two fields, name and email, where both fields are required using the binding: "required" tags. They also have a json tag to determine the JSON key representation of this field. To be valid, an incoming request must look like this:

{
    "email": "anuradha@example.com",
    "name": "Anuradha"
}

If any of these two fields are missing or empty (more on that later), then the c. The shouldBind method will throw an error.

Here, Gin will first unmarshal the request's body to the given DataRequest variable, which can fail, for example, if the body is not JSON. Then, if the unmarshal is successful, Gin will run its validator on the now-filled struct.

#ERROR

In the previous example, we respond with a 400 Bad Request with no additional information if the unmarshalling or validation fails. Let's see what kind of error is returned if the validation fails. For that, we'll log the error using zero logs as our logging library:

func PostRequiredData(p *gin.Context) {
	var d dataToBeRequested

	if err := p.ShouldBind(&d); err != nil {
                       log.Info().Err(err).Msg("field validation is failed")
		p.JSON(http.StatusBadRequest, gin.H{"error": "field validation is failed"})
		return
	}
	
}

Here we have the string representation of our error. It describes everything wrong with our struct's values. There are several issues with that format:

INF field validation is failed error="Key: 'dataToBeRequested.Email' Error:Field validation for 'Email' is failed on the 'required' tag\nKey: 'dataToBeRequested.Name' Error:Field validation for 'Name' is failed on the 'required' tag"
  1. We have struct field names in that error, not the actual JSON tag associated with the field. The error is entirely opaque for our users, if our JSON struct tag doesn't match the field name.
  2. It gives out too many details. 
  3. Errors are separated with \n, that's great for text-based responses or even logging, but it won't work well with JSON.

#ValidatorError

Now we have already seen the string representation of our error. That makes more sense because, in Go, errors must implement the error interface defined like so:

type error interface {
    Error() string
}

So when we log it using our logging library, it will show us the string representation of that error, the one we can read and make sense of. But that's not the actual error. We know that Gin's validator will return the validator. ValidationErrors if a validation error occurs, it will just send back the error it encountered. And what we can do now is called type assertion:

func PostRequiredData(p *gin.Context) {
var d dataToBeRequested

 
if err := p.ShouldBind(&d); err != nil {
        
            if validationErr, ok := err.(validator.ValidationErrors); ok {
                log.Info().Err(validationErr).Msg("this is a validation error")
            }
        
p.JSON(http.StatusBadRequest, gin.H{"error": "bad request"})
return
}

}

This means that we know err is an error (that implements the error interface), but we also suspect it's a validator.ValidationErrors, so we try to assert the error type to access the underlying validator.

A type assertion provides access to an interface value’s underlying concrete value. Validation errors that implement error. If the type assertion fails, then it's not a validation issue, and we can define another behavior, for example, if the request body is an invalid JSON.

Gin’s Validator Customization

Gin is using go-playground/validator internally, but it's possible to access Gin's validator instance to customize it. In fact, this is even shown in the documentation:

func main() {
route := gin.Default()

 
if ve, ok := binding.Validator.Engine().(*validator.Validate); ok {
        
}
    .
route.Run(":8085")
}

We don't want to add custom validators, though, we want to access the JSON tag instead of our struct field. Well, lucky for us, RegisterTagNameFunc exists in the validator lib! So let's register our tag name func:

if ve, ok := binding.Validator.Engine().(*validator.Validate); ok {
    ve.RegisterTagNameFunc(func(fld reflect.StructField) string {
        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
        if name == "-" {
            return ""
        }
        return name
    })
}

RegisterTagNameFunc expects a func(fld reflect.StructField) string function. Here we're telling Gin's validator instance that the f.Field() method we used earlier should not return the struct field name but the associated JSON tag (omitting everything after the coma if there is one).

And just like that, our API now returns:

{
    "errors": {
        "email": "required",
        "name": "required"
    }
}

You won't need to seek separate code blocks that handle basic validation because Gin's validation model via struct will allow you to examine data structures and their validation criteria.

This was all about Validating Forms with Gin. Let's now discuss some frequently asked questions.

Frequently Asked Questions

What is Golang used for?

Go (also known as Golang or Go language) is an open-source general-purpose computer language. Go was designed in 2007 at Google. It is a statically typed language. Robert Griesemer, Rob Pike, and Ken Thompson designed Go to increase programming productivity. 

What is Gin?

Gin is an HTTP web framework written in the Go programming language and which is high-performance in nature.

What is the main advantage of GoLang?

Google engineers created Go in order to construct stable and efficient software. Go is statically typed and explicit. It is most closely modeled after the C language.

In Golang, how big is a pointer?

 A pointer is typically the same size as the architecture of your system, 32 bits on a 32-bit system and 64 bits on a 64-bit system.

Is Gin a Web server?

Gin is a Go-based web framework (Golang). Thanks to httprouter, it has a martini-like API with up to 40 times quicker performance. Gin will be helpful if you require productivity and performance.

Conclusion

This blog was meant to introduce you to Validating Forms with Gin. In this blog, we discussed the validators like struct tags and errors and validating errors with examples. To enhance your understanding, you can refer to these articles:

Refer to our guided paths on Coding Ninjas Studio to learn more about DSA, Competitive Programming, JavaScript, System Design, etc. Enroll in our courses and refer to the mock test and problems available. Take a look at the interview experiences and interview bundle for placement preparations.

Do upvote our blog to help other ninjas grow.

Happy Learning!

 

Live masterclass