How to validate request in Gin with Golang
Golang is an amazing language, and gin is a great backend framework to use. Conceptually, it has no differences than the any backend framework we used in other languages. But its documentation does cause some problems for a accomplish a simple thing like request validation. Here, I will share my findings in terms of how to grab the value and validation in gin.
There are 2 models here for request validation here.
- You get the value first using
ctx.Param("userId")
, then validate by yourself.- You bind the request to struct, and do retrieve/validation in one go using
ctx.Bind()
orctx.ShouldBind()
.
I won’t cover the 1st part, since you would rarely want to do that, but if you prefer code style validation to string like struct-binding, then combine with ozzo-validation might not be that bad.
The 2nd way is idiomatic-gin, and leads to less code. I suggest you look into it.
2nd way, use struct-binding to grab and validate in one go.
Gin
is using a package called validator to do the struct-binding.
For the path param
Let’s say you want to grab the userId
and action
from /user/:userId/*action
, and making sure they always there, you also want to make sure that the userId
is a valid uuid
. You can do something like this.
1 | type RequestParam struct { |
It’s easy to digest, for example, the UserId
field, has a meta data attached to it: uri:"userId", binding:"required,uuid"
uri:"userId"
means grab the value fromuri
which means a path parameter.binding:"required,uuid"
means we willbind
this value to the struct’s propertyUserId
, and it is arequired
field, and we expect its type to beuuid
.
Then in the handler, you use c.BindUri()
to do the getting and validation in one go.
If you want to use some other types other than uuid
, check the validator
‘s documentation.
For the query strings
For example, to get the userId
from /user?userId=aaa-bbb-ccc-ddd
You just use this struct.
1 | type getUserByIdUri struct { |
And both ctx.Bind()
or ctx.BindQuery()
would do the trick for you.
For the json body
For example, to get the {"name":"albert", "birthday": "06/30"}
of the request body, you would use:
1 | type RequestBody struct { |
For getting/validation, ctx.Bind()
and ctx.BindJson()
are your friends.
What about using one struct for combining the path param/query string/body part?
No, you can not, just call the Bind
methods for multiple times.
1 | var reqBody RequestBody |
This is a lot of code, but actually the validation logic is declarative, unless you are dealing with a custom validation which validator package is different.
For validating the different type
Just swap the uuid
to something else in the documentation.
For example:
- an email:
binding:"required,email"
- an timezone:
binding:"required,timezone"
- an datetime:
binding:"required,datetime=2006/01/02"
If you want to use some other types other than uuid
, check the validator
‘s documentation.
End
Hope it helps, thanks.