Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Validating Data Structures And Variables In Golang

TwitterFacebookRedditLinkedInHacker News

When working with Go or any programming language for that matter, there is almost aways a need to validate the data that the user provides before you start working with it or storing it in a database. A sloppy way to validate data would be to use a series of if/else conditions, switch statements, and a bunch of regular expressions, but there are better ways to get the job done without having a disaster of a codebase in terms of maintainability.

We’re going to see how to use the validator.v9 package in Golang to validate native Go data structures, their fields, and any variables that don’t quite fit in.

Before we start validating data, let’s come up with a simple scenario that might be realistic. Let’s assume that we’re building an API like demonstrated in a previous tutorial I wrote titled, Create a Simple RESTful API with Golang. In this API we might have a User data structure that will eventually be written or read from a database.

Let’s assume we have a User data structure that looks like the following:

type User struct {
    ID        string   `json:"id"`
    Firstname string   `json:"firstname"`
    Lastname  string   `json:"lastname"`
    Username  string   `json:"username"`
    Password  string   `json:"password"`
    Type      string   `json:"type"`
}

Rather than just accepting a JSON payload and inserting it into the database, we want to make sure our validation rules are met. We want to make sure that Firstname and Lastname are present, the ID is a UUID, that Username is an email address, and that Password is a certain length. The Type property must never be populated directly by a user because we’ll be defining that in our code. Not the most extravagant requirements, but they are what we need.

So what we can do is download the validator.v9 package with the following command:

go get gopkg.in/go-playground/validator.v9

Now that we have a validator package, we can make some adjustments to our Go data structure to meet our rule requirements. We can add more annotations to represent our validation rules like such:

type User struct {
    ID        string   `json:"id,omitempty" validate:"omitempty,uuid"`
    Firstname string   `json:"firstname" validate:"required"`
    Lastname  string   `json:"lastname" validate:"required"`
    Username  string   `json:"username" validate:"required,email"`
    Password  string   `json:"password" validate:"required,gte=10"`
    Type      string   `json:"type,omitempty" validate:"isdefault"`
}

So how do we enforce these validation rules?

The first thing we want to do is validate the entire data structure based on our annotations. Let’s assume the following in a main function:

func main() {
    user := User{
        Firstname: "Nic",
        Lastname: "Raboy",
        Username: "test@example.com",
        Password: "1234567890",
    }
    validate := validator.New()
    err := validate.Struct(user)
    if err != nil {
        fmt.Println(err.Error())
    }
}

In the above example, the instance of our data structure would succeed in the validation process. We don’t have an ID, but if we did it would need to be a UUID. We don’t have a Type because we’re expecting the default value for a string. No errors should be presented. If we did have an error when we called validate.Struct then we could print them out.

While in most circumstances our validation rules on a data structure will remain pretty consistent, but in some scenarios we may need to make exceptions. For example, inserting data should follow our rules, but what if we want to update data in the database? Should we really enforce the same rules? What if the user wants to login which would require they provide only the Username and Password of the User data structure? In this scenario we can try something different.

Take the following changes to our main function:

func main() {
    user := User{
        Firstname: "Nic",
        Lastname: "Raboy",
        Username: "test@example.com",
        Password: "1234567890",
    }
    validate := validator.New()
    err := validate.StructExcept(user, "Firstname", "Lastname")
    if err != nil {
        fmt.Println(err.Error())
    }
}

Notice that this time around we’re using StructExcept which would exclude Firstname and Lastname from our data validation. This means that only the other fields would be validated, which is good because chances are only the Username and Password are being provided.

Now let’s say that you don’t want to validate your data structures, you want to validate random variables in your code. You could easily do this like the following:

password := "123456"
validate := validator.New()
err := validate.Var(password, "required,gte=10")
if err != nil {
    fmt.Println(err.Error())
}

In the above example we have a string and we are validating it using the given rules. It has a value, but it isn’t greater than or equal to ten characters, so it will fail and show errors.

Conclusion

You just saw how to do some very simple data validation in Golang for data structures as well as variables using the validator.v9 package. If you read the official documentation for the package, you’ll see that there are quite a few validators that can be used. You can even do struct level validation where your data structures have nested data structures within them rather than basic types.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.