The Request object offers excellent request validation capabilities by binding the v tag to struct attributes. Since the underlying validation functionality is achieved through the gvalid module, for more detailed validation rules and introduction, please refer to the Struct Validation - Example section.

Request - Validation - 图1warning

The way of transforming request parameters to structs in the example code below applies to framework v1. From version v2, it is recommended to implement automated parameter struct transformation and validation through standard routes: Standard Router

Example 1, Basic Usage

We will adjust the previous example to add the v validation tag.

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/net/ghttp"
  5. )
  6. // RegisterReq Register request data structure
  7. type RegisterReq struct {
  8. Name string `p:"username" v:"required|length:4,30#Please enter an account|Account length should be between {min} and {max} characters"`
  9. Pass string `p:"password1" v:"required|length:6,30#Please enter the password|Password length is insufficient"`
  10. Pass2 string `p:"password2" v:"required|length:6,30|same:password1#Please confirm the password|Password length is insufficient|Passwords do not match"`
  11. }
  12. // RegisterRes Register response data structure
  13. type RegisterRes struct {
  14. Code int `json:"code"`
  15. Error string `json:"error"`
  16. Data interface{} `json:"data"`
  17. }
  18. func main() {
  19. s := g.Server()
  20. s.Group("/", func(group *ghttp.RouterGroup) {
  21. group.ALL("/register", func(r *ghttp.Request) {
  22. var req *RegisterReq
  23. if err := r.Parse(&req); err != nil {
  24. r.Response.WriteJsonExit(RegisterRes{
  25. Code: 1,
  26. Error: err.Error(),
  27. })
  28. }
  29. // ...
  30. r.Response.WriteJsonExit(RegisterRes{
  31. Data: req,
  32. })
  33. })
  34. })
  35. s.SetPort(8199)
  36. s.Run()
  37. }

In this example, we define two structs: RegisterReq for receiving parameters and RegisterRes for returning data. Since the API returns a JSON data structure, you can see that only the returned struct has the json tag, while the receiving struct only has the p tag. This is because RegisterReq is only used for receiving parameters and does not need to set the returned json tag.

Request - Validation - 图2tip

The p tag is optional; by default, property name matching and conversion are performed under the ignore special characters and case-insensitive rules, meeting most business scenarios’ needs by default.

For demonstration purposes, the RegisterReq object is returned in the normal return result Data property. Since this object does not have a bound json tag, the returned JSON fields will match its property names.

After executing, we use the curl tool to test:

  1. $ curl "http://127.0.0.1:8199/register?name=john&password1=123456&password2=123456"
  2. {"code":0,"error":"","data":{"Name":"john","Pass":"123456","Pass2":"123456"}}
  3. $ curl "http://127.0.0.1:8199/register?name=john&password1=123456&password2=12345"
  4. {"code":1,"error":"Password length is insufficient","data":null}
  5. $ curl "http://127.0.0.1:8199/register"
  6. {"code":1,"error":"Please enter an account","data":null}

Example 2, Validation Error Handling

Request - Validation - 图3tip

In the latest version, only the first error is returned.

As shown in the above example, when a request validation error occurs, all validation failure errors are returned, which may not be very user-friendly. When an error occurs, we can convert the validation error into a gvalid.Error API object and then control the error return flexibly.

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/net/ghttp"
  5. "github.com/gogf/gf/v2/util/gvalid"
  6. )
  7. type RegisterReq struct {
  8. Name string `p:"username" v:"required|length:4,30#Please enter an account|Account length should be between {min} and {max} characters"`
  9. Pass string `p:"password1" v:"required|length:6,30#Please enter the password|Password length is insufficient"`
  10. Pass2 string `p:"password2" v:"required|length:6,30|same:password1#Please confirm the password|Password length is insufficient|Passwords do not match"`
  11. }
  12. type RegisterRes struct {
  13. Code int `json:"code"`
  14. Error string `json:"error"`
  15. Data interface{} `json:"data"`
  16. }
  17. func main() {
  18. s := g.Server()
  19. s.Group("/", func(group *ghttp.RouterGroup) {
  20. group.ALL("/register", func(r *ghttp.Request) {
  21. var req *RegisterReq
  22. if err := r.Parse(&req); err != nil {
  23. // Validation error.
  24. if v, ok := err.(gvalid.Error); ok {
  25. r.Response.WriteJsonExit(RegisterRes{
  26. Code: 1,
  27. Error: v.FirstError().Error(),
  28. })
  29. }
  30. // Other error.
  31. r.Response.WriteJsonExit(RegisterRes{
  32. Code: 1,
  33. Error: err.Error(),
  34. })
  35. }
  36. // ...
  37. r.Response.WriteJsonExit(RegisterRes{
  38. Data: req,
  39. })
  40. })
  41. })
  42. s.SetPort(8199)
  43. s.Run()
  44. }

As shown, when an error occurs, we can use the err.(gvalid.Error) assertion method to determine whether the error is a validation error. If so, the first validation error is returned instead of all. For more detailed error control methods, please refer to the Data Validation - Result section.

Request - Validation - 图4tip

Moreover, we can use gerror.Current to obtain the first error message instead of using the assertion judgment. For example:

  1. var req *RegisterReq
  2. if err := r.Parse(&req); err != nil {
  3. r.Response.WriteJsonExit(RegisterRes{
  4. Code: 1,
  5. Error: gerror.Current(err).Error(),
  6. })
  7. }

After executing, we test using the curl tool:

  1. $ curl "http://127.0.0.1:8199/register"
  2. {"code":1,"error":"Please enter an account","data":null}
  3. $ curl "http://127.0.0.1:8199/register?name=john&password1=123456&password2=1234567"
  4. {"code":1,"error":"Passwords do not match","data":null}