英文:
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:"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"`
}
// sample routers with a common middleware validator function
router.POST("/login", ReqValidate("LoginRequestBody"), LoginController)
router.POST("/signup", ReqValidate("SignupReqBody"), SignupController)
func ReqValidate(<something>) 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 (
"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")
}
答案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 <something>
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{"error": err.Error()})
return
}
next(c, params)
}
}
And then the controllers:
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) {
// ...
}
And then the routing:
router := gin.Default()
router.POST("/login", ReqValidate(LoginController))
router.POST("/signup", ReqValidate(SignupController))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论