当前位置:网站首页>Getting started with go web programming: validators
Getting started with go web programming: validators
2022-06-22 14:01:00 【51CTO】
Preface
Network authentication can be a challenge . There is a saying in Web Principles that are widely circulated in development :
We can't trust anything from the client user form .
So we have to validate all the incoming data before using it . Realization REST API yes Go Typical use cases for applications . API The accepted data with wrong format may cause serious errors in other parts of the system .
The best case scenario is that your database has mechanisms to prevent the storage of malformed data . If you don't do that , This data can cause errors and unexpected behavior in your customer facing applications ( such as SQL Inject ).
In this article , We'll show you how to Go Send validation to REST API The data of .
Manually verify the input
Simple REST API
This is an easy one REST API Example , Use gorilla/mux Package building . It's a great HTTP Router , Especially for REST API. API Provide a path for an endpoint /user. For the sake of simplicity , It only accepts... From all users HTTP GET And create a user's HTTP Post. Besides , It has no persistent database , Instead, you use slices to store users in memory .
package
main
import (
"encoding/json"
"log"
"net/http"
"strings"
"github.com/gorilla/mux"
)
type
User
struct {
ID
int
FirstName
string
LastName
string
FavouriteVideoGame
string
Email
string
}
func
main() {
router :
=
mux
.
NewRouter()
router
.
HandleFunc(
"/user",
PostUser)
.
Methods(
http
.
MethodPost)
router
.
HandleFunc(
"/user",
GetUsers)
.
Methods(
http
.
MethodGet)
log
.
Fatal(
http
.
ListenAndServe(
":8081",
router))
}
var
users
= []
User{}
var
id
=
0
func
validateEmail(
email
string)
bool {
// This is obviously not a good validation strategy for email addresses
// pretend a complex regex here
return
!
strings
.
Contains(
email,
"@")
}
func
PostUser(
w
http
.
ResponseWriter,
r
*
http
.
Request) {
user :
=
User{}
json
.
NewDecoder(
r
.
Body)
.
Decode(
&
user)
// We don't want an API user to set the ID manually
// in a production use case this could be an automatically
// ID in the database
user
.
ID
=
id
id
++
users
=
append(
users,
user)
w
.
WriteHeader(
http
.
StatusCreated)
}
func
GetUsers(
w
http
.
ResponseWriter,
r
*
http
.
Request) {
w
.
Header()
.
Add(
"Content-Type",
"application/json")
if
err :
=
json
.
NewEncoder(
w)
.
Encode(
users);
err
!=
nil {
log
.
Println(
err)
w
.
WriteHeader(
http
.
StatusInternalServerError)
return
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
Now let's look at how to manually validate what is provided to this in the request body API Of POST Input to the handler .
Manually verify the input
Sometimes we ask the user to enter some fields , But they failed to complete the field . For example, in the previous section , When we need a user name . You can use len Function to get the length of the field , To ensure that the user has entered something .
Suppose we want to use Post When the handler creates a user, it sets up FirstName、LastName and Email. Besides , We want the email field to be a valid email address . An easy way to do this is to manually validate fields , As shown below :
if
user
.
FirstName
==
"" {
errs
=
append(
errs,
fmt
.
Errorf(
"Firstname is required")
.
Error())
}
if
user
.
LastName
==
"" {
errs
=
append(
errs,
fmt
.
Errorf(
"LastName is required")
.
Error())
}
if
user
.
Email
==
""
||
validateEmail(
user
.
Email) {
errs
=
append(
errs,
fmt
.
Errorf(
"A valid Email is required")
.
Error())
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
Complete example :
package
main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"github.com/gorilla/mux"
)
type
User
struct {
ID
int
FirstName
string
LastName
string
FavouriteVideoGame
string
Email
string
}
func
main() {
router :
=
mux
.
NewRouter()
router
.
HandleFunc(
"/user",
PostUser)
.
Methods(
http
.
MethodPost)
router
.
HandleFunc(
"/user",
GetUsers)
.
Methods(
http
.
MethodGet)
log
.
Fatal(
http
.
ListenAndServe(
":8081",
router))
}
var
users
= []
User{}
var
id
=
0
func
validateEmail(
email
string)
bool {
// That's obviously not a good validation strategy for email addresses
// pretend a complex regex here
return
!
strings
.
Contains(
email,
"@")
}
func
PostUser(
w
http
.
ResponseWriter,
r
*
http
.
Request) {
user :
=
User{}
json
.
NewDecoder(
r
.
Body)
.
Decode(
&
user)
errs :
= []
string{}
if
user
.
FirstName
==
"" {
errs
=
append(
errs,
fmt
.
Errorf(
"Firstname is required")
.
Error())
}
if
user
.
LastName
==
"" {
errs
=
append(
errs,
fmt
.
Errorf(
"LastName is required")
.
Error())
}
if
user
.
Email
==
""
||
validateEmail(
user
.
Email) {
errs
=
append(
errs,
fmt
.
Errorf(
"A valid Email is required")
.
Error())
}
if
len(
errs)
>
0 {
w
.
Header()
.
Add(
"Content-Type",
"application/json")
w
.
WriteHeader(
http
.
StatusBadRequest)
if
err :
=
json
.
NewEncoder(
w)
.
Encode(
errs);
err
!=
nil {
}
return
}
// We don't want an API user to set the ID manually
// in a production use case this could be an automatically
// ID in the database
user
.
ID
=
id
id
++
users
=
append(
users,
user)
w
.
WriteHeader(
http
.
StatusCreated)
}
func
GetUsers(
w
http
.
ResponseWriter,
r
*
http
.
Request) {
w
.
Header()
.
Add(
"Content-Type",
"application/json")
if
err :
=
json
.
NewEncoder(
w)
.
Encode(
users);
err
!=
nil {
log
.
Println(
err)
w
.
WriteHeader(
http
.
StatusInternalServerError)
return
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
You can see that this verification method is very verbose . We have to define a custom function to validate common things , Like email addresses . Let's see how to improve this .
It's just a simple pass validateEmail Function to verify whether the mailbox contains @ character :
In fact, a better way is to use regular expressions to verify E-mail The effectiveness of the :
Use the structure tag to validate the input
stay Go A more common way to validate structures in is to use structure tags . There are many packages that perform structure validation through structure tags . We will use... Here https://github.com/go-playground/validator: The Validator Implement structure and single field value validation based on tags .

Use go get github.com/go-playground/validator/v10 Installation .
This not only enables us to use structure tags for verification , It also provides a number of predefined validation methods , An E-mail address, for example .
We will perform this verification on the structure , But it doesn't discuss how to fill the structure . We can assume that the data will be parsed JSON Payload 、 Enter explicit padding or other methods from the form to populate .
If your data needs another validator , Please check the documentation of the validator package . The verifier you need is most likely provided in the package 80 Under multiple validators .
package
main
import (
"encoding/json"
"log"
"net/http"
"github.com/go-playground/validator/v10"
"github.com/gorilla/mux"
)
type
User
struct {
ID
int
`validate:"isdefault"`
FirstName
string
`validate:"required"`
LastName
string
`validate:"required"`
FavouriteVideoGame
string
Email
string
`validate:"required,email"`
}
func
main() {
router :
=
mux
.
NewRouter()
router
.
HandleFunc(
"/user",
PostUser)
.
Methods(
http
.
MethodPost)
router
.
HandleFunc(
"/user",
GetUsers)
.
Methods(
http
.
MethodGet)
log
.
Fatal(
http
.
ListenAndServe(
":8081",
router))
}
var
users
= []
User{}
var
id
=
0
func
PostUser(
w
http
.
ResponseWriter,
r
*
http
.
Request) {
user :
=
User{}
json
.
NewDecoder(
r
.
Body)
.
Decode(
&
user)
validate :
=
validator
.
New()
err :
=
validate
.
Struct(
user)
if
err
!=
nil {
validationErrors :
=
err
.(
validator
.
ValidationErrors)
w
.
Header()
.
Add(
"Content-Type",
"application/json")
w
.
WriteHeader(
http
.
StatusBadRequest)
responseBody :
=
map[
string]
string{
"error":
validationErrors
.
Error()}
if
err :
=
json
.
NewEncoder(
w)
.
Encode(
responseBody);
err
!=
nil {
}
return
}
// We don't want an API user to set the ID manually
// in a production use case this could be an automatically
// ID in the database
user
.
ID
=
id
id
++
users
=
append(
users,
user)
w
.
WriteHeader(
http
.
StatusCreated)
}
func
GetUsers(
w
http
.
ResponseWriter,
r
*
http
.
Request) {
w
.
Header()
.
Add(
"Content-Type",
"application/json")
if
err :
=
json
.
NewEncoder(
w)
.
Encode(
users);
err
!=
nil {
log
.
Println(
err)
w
.
WriteHeader(
http
.
StatusInternalServerError)
return
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
above validationError.Error() Returns a string , This string summarizes each failed validation in the structure . therefore BadRequest The response still has very detailed information about what went wrong .
We changed validation to use the validator package , Now verify according to the following rules :
- ID Fields should not be set by the user , So we verify that it has int The default value of , namely 0
- FullName and LastName It's necessary
- Email fields are required , And use a predefined email validator to verify
Use a custom validator to validate input
So now we use the validator package and use the structure tag to validate the structure . But how do we verify a structure field that cannot be verified by the tag provided by the library ?
Suppose we want to blacklist some video games . Because we don't want anyone in our system to like PUBG or Fortnite Waiting for game users . under these circumstances , We can define a custom validate Mark values and let validate The package uses it like this :
First, we define a validation function :
Then we use the validator instance to register the function and the corresponding tag .
Now we are User Add a label to the definition of the structure .
Recommended validation Libraries
Awesome Go Under the project, there are libraries for verification . Here are the recommendations :

- checkdigit - Provide check digit algorithms (Luhn, Verhoeff, Damm) and calculators (ISBN, EAN, JAN, UPC, etc.).
- gody - :balloon: A lightweight struct validator for Go.
- govalid - Fast, tag-based validation for structs.
- govalidator - Validators and sanitizers for strings, numerics, slices and structs.
- govalidator - Validate Golang request data with simple rules. Highly inspired by Laravel’s request validation.
- jio - jio is a json schema validator similar to joi.
- ozzo-validation - Supports validation of various data types (structs, strings, maps, slices, etc.) with configurable and extensible validation rules specified in usual code constructs instead of struct tags.
- terraform-validator - A norms and conventions validator for Terraform.
- validate - Go package for data validation and filtering. support validate Map, Struct, Request(Form, JSON, url.Values, Uploaded Files) data and more features.
- validate - This package provides a framework for writing validations for Go applications.
- validator - Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving.
- Validator - A lightweight model validator written in Go.Contains VFs:Min, Max, MinLength, MaxLength, Length, Enum, Regex.
According to the introduction, pick one of your own projects ~
summary
verification REST API Input is critical to prevent malformed data in your application . You can write your own validation logic , But in most cases , It is best to use a well maintained validation package , For example, the above recommendation .
This allows you to use tags in the structure to configure authentication , And keep the logic of running validation simple . If you have a special use case that requires unusual validation capabilities , You can still define your own extensions for the validator package .
- Package validatorValidation
- Awesome Go:https://awesome-go.com/validation/
- Client-side form validation
- Validate REST Input in Go
- Verification of inputs
边栏推荐
- Oracle's skills in dealing with inserting duplicate records
- leetcode 11. Container with the most water
- HMS core news industry solution: let technology add humanistic temperature
- HMS Core新闻行业解决方案:让技术加上人文的温度
- 软件项目验收测试范围和流程,这些你都知道吗?
- Leetcode union search set
- Chapter 1 overview of naturallanguageprocessing and deep learning
- Seven cattle cloud upload picture
- Kubernetes monitoring: grafana adds datasource and dashboard through automation
- Eureka的InstanceInfoReplicator类(服务注册辅助类)
猜你喜欢

别再用 System.currentTimeMillis() 统计耗时了,太 Low,StopWatch 好用到爆!

技术实践 | 场景导向的音视频通话体验优化

防火墙基础之策略部署

Configuring cplex12.4 tutorial in VS2010

HMS core news industry solution: let technology add humanistic temperature

Acwing 241 Loulan totem (detailed explanation of tree array)

leetcode-子序列/子串问题

Nine good programming habits for 10 years

Leetcode dichotomy
MySQL如何让一个表中可以有多个自增列
随机推荐
安装和使用protobuf-c
"Dare not doubt the code, but have to doubt the code" a network request timeout analysis
Implementation of connecting SQL server to Oracle server_ Including query implementation
Acwing game 55
能让Jellyfin直接挂载阿里云盘的aliyundrive-fuse
SQL Server common functions
Instanceinforeplicator class of Eureka (service registration auxiliary class)
Offline physical stores combined with VR panorama make virtual shopping more realistic
机器人方向的刚性需求→个人思考←
Consolidation of common functions of numpy Library
Which securities company is good for retail investors to open an account? Is it safe to open a mobile account?
Query rewriting for opengauss kernel analysis
Leetcode dichotomy
坚持了 10 年的 9 个编程好习惯
History of hash index design
client-go gin的简单整合九-Create
Some common SQL (version 05 and above) database maintenance scripts
polardbx是pg还是mysql?
Number of times Oracle uses cursor to decompose numbers
Stored procedures in MySQL
