Adding Validator.v9

💭 Form validation is an important step while inserting and updating data. In the Go ecosystem we can see few validation packages like go-playground/validator.v9 , go-ozzo/ozzo-validation . In here, we are using playground/validator.v9 due to its simplicity of usage.

Adding initial validator

▸ We need to run go get gopkg.in/go-playground/validator.v9 to download and install the package. As you know, this updates go.mod and go.sum files as well.

▸ Let’s create util/validator/validator.go to get the *validator.Validate with a custom configuration. By default, it uses validate struct field tags to read meta data. But, in here, we replace it with form struct field tags.

▸ To use this *validator.Validate as the global validator, let’s add this to App struct in app/app/app.go .

▸ Then, we need to update cmd/app/main.go to get this *validator.Validate at the startup of the application.

▸ Let’s add validation rules to the BookForm struct in the model/book.go .

💡 You can see all list of validation rule types, supported by playground/validator.v9 in https://github.com/go-playground/validator/blob/v9/baked_in.go#L64.

▸ Then, let’s add validations to the HandleCreateBook() and HandleUpdateBook() methods in the app/app/bookHandler.go .

▸ Rebuild and rerun the application. You should see error messages like following messages, while inserting invalid data.

{

"error": "Key: 'BookForm.Title' Error:Field validation for 'Title' failed on the 'required' tag"

}

💭 As you can see, those are not having valid JSON formats. And also messages are not suitable to show to the end user. So, we will add custom messages for these in the next section.

Implementing custom validation messages

We need to fix two things in the default error messages of playground/validator.v9 .

01. It shows struct field names, instead of names in json tags; ( “Field validation for ‘Title’ failed” instead “Field validation for ‘title’ failed” ).

🔎 We can see the solution in https://github.com/go-playground/validator/blob/173026262523a492668bd6d78b8934c2ad69843f/validator_instance.go#L122 .

02. The error response is not having a valid JSON format and error messages are not suitable to show to the end users.

🔎 The solution playground/validator.v9 developers suggest is to use its go-playground/validator/translations package. But due to we don’t need to support multiple translations in our API application, we will write ToErrResponse() function in util/validator/validator.go to convert the default error messages to a valid JSON format with end user friendly error messages. However better check their implementation in https://github.com/go-playground/validator/blob/v9/translations/en/en.go.

▸ Let’s update util/validator/validator.go to fix both above issues.

▸ Then let’s update app/app/bookHandler.go .

⭐ As you can see, we duplicate 20 lines of code in each handler and it is not a good practice. 👨‍🏫 Assume this as the homework and find how we can remove these duplicates. 🔎 One way is, moving these codes to a private method in app/app/common.go .

▸ We save those static error messages in app/app/app.go .

const appErrFormErrResponseFailure = "form error response failure"

▸ Rebuild and rerun the application. Now, you should see error messages like these.

{

"errors": [

"title is a required field",

"author must be a maximum of 255 in length",

"image_url must be a valid URL"

]

}

Implementing custom validation types

▸ One last thing! We don’t fully validate the author’s name and the published date of the BookForm struct . For the moment playground/validator.v9 is not supporting “alphabetic characters with space” and “date” validations. So, let’s create a custom validation types for these in util/validator/validator.go .

▸ Then, we need to update BookForm struct in model/book.go .

▸ Rebuild and rerun the application. Now, you should get validation errors even for author and image_url .