uAdmin the Golang Web Framework #5 Validation

IMPORTANT (BEFORE YOU START)

If you installed uAdmin before November 7th version 0.1.0-alpha, please update your uAdmin installation (If you are not sure, just update it anyway):
go get -u github.com/uadmin/uadmin/...
After you do that go to your project’s folder and run:
uadmin prepare
This will update uAdmin templates and static files.

Front-End Validation

Validation for user input in uAdmin can be done in front-end and back-end. There are a few things that we can validate depending in the field data type.

First validation is required which works on all data types. Let’s make a few fields required in out app. Open /models/todo.go and make both Name and TargetDate required.

type Todo struct {
uadmin.Model
Name string `uadmin:"required"`
Description string `uadmin:"html"`
TargetDate *time.Time `uadmin:"required"`
Progress int `uadmin:"progress_bar:30:red,70:yellow,100:green"`
Task Task
TaskID uint
}

Compile and run your app again:

$ go build; ./todo

When you open a todo record you will see that both fields are required:

Notice there is a red asterisk to required fields and if you try to save without filling a required field, it will ask you to fill the field first.

Next is max and min validations and these work for numeric fields. I want to limit my progress between 0–100. The way I can do that is to add these validations as a tags to Progress field in /models/todo.go.

type Todo struct {
uadmin.Model
Name string `uadmin:"required"`
Description string `uadmin:"html"`
TargetDate *time.Time `uadmin:"required"`
Progress int `uadmin:"progress_bar:30:red,70:yellow,100:green;min:0;max:100"`
Task Task
TaskID uint
}

Notice that you can add more tags inside your uadmin tag by separating them with a semicolon. In Progress we have now three tags, progress_bar, min and max. Not compile and run again and you will notice that you cannot put any values outside of that range (0–100).

Next is pattern which is the most powerful front-end validation tag which works for string fields. The way it works is using Regular Expression. Let’s add a validation for Name fields in /models/todo.go to limit the number of letters in the name to 5–100 letters. We can add an optional message with that validation which using pattern_msg tag. To do that open /models/todo.go and add this tag:

type Todo struct {
uadmin.Model
Name string `uadmin:"required;pattern:.{5,100};pattern_msg:Name length should be 5-100 letters"`
Description string `uadmin:"html"`
TargetDate *time.Time `uadmin:"required"`
Progress int `uadmin:"progress_bar:30:red,70:yellow,100:green;min:0;max:100"`
Task Task
TaskID uint
}

Now compile and run again and you will get extra validation for the Name fields:

Back-end Validation

For more advanced validation, sometimes you need to implement some validation from the back-end. This is the case for validation that required access to the database to check for duplicate entries or check some permissions like “You are not allowed to assign this task to people outside your department”. Regardless of the case this is how to implement back-end validation.

let’s say we don’t want people to add duplicate entries for todo. The way we will do that is check the database and see if there is another todo record with the same name. If we find another record, we can return a message that tells the user that the todo item has been added to the system already.

Open /models/todo.go and add a new method called Validate to your Todo struct.

type Todo struct {
uadmin.Model
Name string `uadmin:"required;pattern:.{5,100};pattern_msg:Name length should be 5-100 letters"`
Description string `uadmin:"html"`
TargetDate *time.Time `uadmin:"required"`
Progress int `uadmin:"progress_bar:30:red,70:yellow,100:green;min:0;max:100"`
Task Task
TaskID uint
}
func (t *Todo) Save() {
// Save the model to DB
uadmin.Save(t)
 // Some other business Logic ...
}
func (t Todo) Validate() (errMsg map[string]string) {
// Initialize the error messages
errMsg = map[string]string{}
  // Get any records from the database that maches the name of
// this record and make sure the record is not the record we are
// editing right now
todo := Todo{}
if uadmin.Count(&todo, "name = ? AND id <> ?", t.Name, t.ID) != 0 {
errMsg["Name"] = "This todo name is already in the system"
}
return
}

Notice that the receiver for Validate() is not a pointer but the struct type. Also notice that the return is a map where the key is the field name and the value is the error message.

If you try now to add a new record with an existing todo record’s name, it will show me this error:

Congrats, you have understand now how to validate user input from the front-end and the back-end.

In Part 6, we will authentication and permissions.