如何在Golang中验证REST API请求的请求体结构

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

how do i validate the body structure of rest api request in golang

问题

我正在尝试确保一个POST请求的请求体具有与示例中完全相同的结构,如果不匹配则应该抛出错误。

例如,我有以下函数:

func UpdatePassword(c *fiber.Ctx) error {

	type UpdatePasswordData struct {
		Password             string `json:"password" form:"password"`
		NewPassword          string `json:"new_password" form:"new_password"`
		NewPasswordConfirm   string `json:"new_password_confirm" form:"new_password_confirm"`
	}

	data := UpdatePasswordData{}

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	var user models.User

	if data.NewPassword != data.NewPasswordConfirm {
		c.Status(400)
		return c.JSON(fiber.Map{
			"message": "passwords do not match",
		})
	}

	email, _ := middlewares.GetUserEmail(c)

	newPassword := models.HashPassword(data.NewPassword)

	database.DB.Model(&user).Select("Password").Where("email = ?", email).Updates(map[string]interface{}{"Password": newPassword})

	return c.JSON(user)
}

POST请求应该使用以下结构的请求体:

{
    "password": "oldpassword",
    "new_password": "newpassword",
    "new_password_confirm": "newpassword"
}

但是当前这个端点接受的请求体不一定具有这个完全相同的结构。那么,我该如何强制请求体的结构匹配,以便如果结构不匹配,就抛出错误呢?

英文:

I am trying to ensure the body of a post request for example contains exact structure of the body and if not ahould throw an error

for example i have the following function

func UpdatePassword(c *fiber.Ctx) error {

	type UpdatePasswordData struct {
		Password  string `json:"password" form:"password"`
		NewPassword string `json:"new_password" form:"new_password"`
		NewPasswordConfirm string `json:"new_password_confirm" form:"new_password_confirm"`
	}
	
	data := UpdatePasswordData{}

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	var user models.User
	
	if data.NewPassword != data.NewPasswordConfirm {
		c.Status(400)
		return c.JSON(fiber.Map{
			"message": "passwords do not match",
		})
	}

	email, _ := middlewares.GetUserEmail(c)

	newPassword := models.HashPassword(data.NewPassword)

	database.DB.Model(&user).Select("Password").Where("email = ?", email).Updates(map[string]interface{}{"Password": newPassword})

	return c.JSON(user)
}

the POST request should be looking for body with this structure

{
    "password": "oldpassword",
    "new_password": "newpassword",
    "new_password_confirm": "newpassword",
}

but currently this endpoint accepts body that does not have this exact structure. So how do i enforce the structure in the body of request, so that if structure does not match, i throw an error?

答案1

得分: 5

不喜欢杜松子酒,Fiber没有内置的验证包。

可以使用go-playground/validator。

go get github.com/go-playground/validator

示例代码:

type UpdatePasswordData struct {
        Password  string `json:"password" validate:"required,min=8,max=32"`
        NewPassword string `json:"new_password" validate:"required,min=8,max=32"`
        NewPasswordConfirm string `json:"new_password_confirm" validate:"eqfield=NewPassword"`
}

func UpdatePassword(c *fiber.Ctx) error {
  var body UpdatePasswordData
  if err := c.BodyParser(&body); err != nil {
    return err
  }

  validate := validator.New()
  if err := validate.Struct(body); err != nil {
    return err
  }

  // 做其他操作
  // 获取当前用户,检查密码是否等于哈希值(body.password)
  // 保存新密码
}

或者你可以查看Fiber官方文档的验证部分:https://docs.gofiber.io/guide/validation#validator-package

英文:

do not like gin, fiber has not builtin validate package

use go-playground/validator

go get github.com/go-playground/validator

example

type UpdatePasswordData struct {
        Password  string `json:"password" validate:"required,min=8,max=32"`
        NewPassword string `json:"new_password" validate:"required,min=8,max=32"`
        NewPasswordConfirm string `json:"new_password_confirm" validate:"eqfield=NewPassword"`
}

func UpdatePassword(c *fiber.Ctx) error {
  var body UpdatePasswordData
  if err := c.BodyParser(&body); err != nil {
    return err
  }

  validate := validator.New()
  if err := validate.Struct(body); err != nil {
    return err
  }

  // do others
  // get current user, check password == hash(body.password)
  // save new passworld
}

or you can see fiber office docs https://docs.gofiber.io/guide/validation#validator-package

答案2

得分: 0

我们可以使用结构体标签 validate:"required" 来确保请求有效载荷中存在所有必填字段。

此外,我们可以使用验证器包提供的标签来验证字段,并且对于额外的验证,我们可以实现自定义验证器并像这样注册它们:

validate := validator.New()
validate.RegisterValidation("password-validator", PasswordValidator)
英文:

We can use struct tag

`validate:"required"`

to ensure that all the mandatory fields are there in the request payload.

Moreover we can validate the fields with the provided tags of the validator package and for additional validations we can implement custom validators and register them like this:

validate := validator.New()
validate.RegisterValidation("password-validator", PasswordValidator) 

huangapple
  • 本文由 发表于 2022年1月4日 12:47:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/70574193.html
匿名

发表评论

匿名网友

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

确定