Go中的HTTP请求验证中间件

huangapple go评论72阅读模式
英文:

HTTP Request Validation Middleware In Go

问题

我正在尝试创建一个通用的HTTP请求验证中间件函数,它接受类型(可能是reflect.Type)作为参数,然后使用github.com/go-playground/validator/v10包将JSON解组为所提到类型的结构体,并验证该结构体。我尝试用以下示例代码来解释...

示例:

type LoginRequestBody struct {
   Username string `json:"username",validate:"required"`
   Password string `json:"password",validate:"required"`
}

type SignupReqBody struct {
   Username string `json:"username",validate:"required"`
   Password string `json:"password",validate:"required"`
   Age      int    `json:"age",validate:"required"`
}

// 带有通用中间件验证函数的示例路由器
router.POST("/login", ReqValidate("LoginRequestBody"), LoginController)
router.POST("/signup", ReqValidate("SignupReqBody"), SignupController)

func ReqValidate(<something>) gin.HandlerFunc {
   return func (c *gin.Context) {
      // 将JSON解组为结构体
      // 通用验证逻辑...
      c.Next()
   }
}

总的来说,我想要实现与Node.js中的Joi包相同的验证器灵活性。

英文:

I am trying to create a common HTTP request validator middleware function that accepts type (maybe reflect.Type) as an argument and then using the package github.com/go-playground/validator/v10 to be able to unmarshall JSON into struct of mentioned type and validate the struct. I've tried to explain with the following example code...

EXAMPLE

type LoginRequestBody struct {
   Username string `json:&quot;username&quot;,validate:&quot;required&quot;`
   Password string `json:&quot;password&quot;,validate:&quot;required&quot;`
}

type SignupReqBody struct {
   Username string `json:&quot;username&quot;,validate:&quot;required&quot;`
   Password string `json:&quot;password&quot;,validate:&quot;required&quot;`
   Age      int    `json:&quot;age&quot;,validate:&quot;required&quot;`
}

// sample routers with a common middleware validator function
router.POST(&quot;/login&quot;, ReqValidate(&quot;LoginRequestBody&quot;), LoginController)
router.POST(&quot;/signup&quot;, ReqValidate(&quot;SignupReqBody&quot;), SignupController)

func ReqValidate(&lt;something&gt;) gin.HandlerFunc {
   return func (c *gin.Context) {
      // unmarshalling JSON into a struct
      // common validation logic...
      c.Next()
   }
}

Overall, i wanna achieve the same validator flexibility as there in Node.js using Joi package.

答案1

得分: 2

我不知道是否需要使用中间件,但我最近尝试做一些事情,找到了一个很好的教程,你可以在这里看到。

使用Gin,你可以使用绑定(binding):

示例:

package main
import (
  "github.com/gin-gonic/gin"
  "net/http"
)
type AnyStruct struct {
   Price uint `json:"price" binding:"required,gte=10,lte=1000"`
}
func main() {
  engine := gin.New()
  engine.POST("/test", func(context *gin.Context) {
     body := AnyStruct{}
     if err := context.ShouldBindJSON(&body); err != nil {
        context.AbortWithStatusJSON(http.StatusBadRequest,
        gin.H{
            "error": "VALIDATEERR-1",
            "message": "Invalid inputs. Please check your inputs"})
        return
     }
     context.JSON(http.StatusAccepted, &body)
  })
  engine.Run(":3000")
}
英文:

I don't know if it is necessary to use middleware but I was recently trying to do something and I found an excellent tutorial that you can see here.

With Gin You can use binding:

Example:

package main
import (
  &quot;github.com/gin-gonic/gin&quot;
  &quot;net/http&quot;
)
type AnyStruct struct {
   Price uint `json:&quot;price&quot; binding:&quot;required,gte=10,lte=1000&quot;`
}
func main() {
  engine:=gin.New()
  engine.POST(&quot;/test&quot;, func(context *gin.Context) {
     body:=AnyStruct{}
     if err:=context.ShouldBindJSON(&amp;body);err!=nil{
        context.AbortWithStatusJSON(http.StatusBadRequest,
        gin.H{
            &quot;error&quot;: &quot;VALIDATEERR-1&quot;,
            &quot;message&quot;: &quot;Invalid inputs. Please check your inputs&quot;})
        return
     }
     context.JSON(http.StatusAccepted,&amp;body)
  })
  engine.Run(&quot;:3000&quot;)
}

答案2

得分: 1

不要使用逗号来分隔结构体标签的键值对,而是使用空格。

你可以使用泛型(类型参数)来替代<something>,但是你的控制器需要将具体类型作为它们的参数。

例如:

func ReqValidate[T any](next func(*gin.Context, *T)) gin.HandlerFunc {
	return func(c *gin.Context) {
		params := new(T)
		if err := c.ShouldBindJSON(params); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		next(c, params)
	}
}

然后是控制器:

type LoginRequestBody struct {
	Username string `json:"username" validate:"required"`
	Password string `json:"password" validate:"required"`
}

func LoginController(c *gin.Context, params *LoginRequestBody) {
	// ...
}

type SignupReqBody struct {
	Username string `json:"username" validate:"required"`
	Password string `json:"password" validate:"required"`
	Age      int    `json:"age" validate:"required"`
}

func SignupController(c *gin.Context, params *SignupReqBody) {
	// ...
}

然后是路由:

router := gin.Default()
router.POST("/login", ReqValidate(LoginController))
router.POST("/signup", ReqValidate(SignupController))
英文:

Don't use commas to separate struct tag key-value pairs, use space.

You can use generics (type parameters) to replace &lt;something&gt; but your controllers need to have the concrete type as their argument.

For example:

func ReqValidate[T any](next func(*gin.Context, *T)) gin.HandlerFunc {
	return func(c *gin.Context) {
		params := new(T)
		if err := c.ShouldBindJSON(params); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{&quot;error&quot;: err.Error()})
			return
		}
		next(c, params)
	}
}

And then the controllers:

type LoginRequestBody struct {
	Username string `json:&quot;username&quot; validate:&quot;required&quot;`
	Password string `json:&quot;password&quot; validate:&quot;required&quot;`
}

func LoginController(c *gin.Context, params *LoginRequestBody) {
	// ...
}

type SignupReqBody struct {
	Username string `json:&quot;username&quot; validate:&quot;required&quot;`
	Password string `json:&quot;password&quot; validate:&quot;required&quot;`
	Age      int    `json:&quot;age&quot; validate:&quot;required&quot;`
}

func SignupController(c *gin.Context, params *SignupReqBody) {
	// ...
}

And then the routing:

router := gin.Default()
router.POST(&quot;/login&quot;, ReqValidate(LoginController))
router.POST(&quot;/signup&quot;, ReqValidate(SignupController))

huangapple
  • 本文由 发表于 2022年11月2日 01:58:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/74279976.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定