PATCH请求的单个字段的HTTP请求验证

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

PATCH http request validation of single field

问题

我有一个类似这样的结构体片段:

type Talent struct {
    Code               string   `json:"code" gorm:"type:varchar(10);not null"`
    FirstName          string   `json:"firstName" example:"Ravi" gorm:"type:varchar(50)"`
    LastName           string   `json:"lastName" example:"Sharma" gorm:"type:varchar(50)"`
    Email              string   `json:"email" example:"john@doe.com" gorm:"type:varchar(100)"`
    Contact            string   `json:"contact" example:"1234567890" gorm:"type:varchar(15)"`
    AcademicYear       *uint8   `json:"academicYear" example:"1" gorm:"type:tinyint(2)"`
    Type               *uint8   `json:"talentType" example:"4" gorm:"type:tinyint(2)"`
    Resume             *string  `json:"resume" gorm:"type:varchar(200)"`
    ExperienceInMonths *uint    `json:"experienceInMonths"`
    Image              *string  `json:"image" gorm:"type:varchar(200)"`
    Gender             *string  `json:"gender" gorm:"type:varchar(50)"`
    DateOfBirth        *string  `json:"dateOfBirth" gorm:"type:date"`
}

我想逐个更新字段,所以我只将一个字段作为 JSON 发送到 API 作为 PATCH HTTP 请求,在后端(使用 Golang)中,我将 JSON 转换为结构体,只有 JSON 中的那个字段会在结构体中有值,其他所有字段都将为 nil。

例如,我发送了 firstName,现在当我将其转换为结构体时,只有 firstName 字段被填充。现在我想要验证该字段,比如 firstName 是一个必填字段,所以它将有两个验证:一个用于检查是否为空,一个用于检查最大字符数。

类似地,所有字段都有一些验证。现在我该如何验证只有特定的字段?我考虑过使用 switch case,但在 Golang 中是否有其他更优的方法来做到这一点?

英文:

I have a struct snippet which is something like this

type Talent struct {
	Code               string   `json:"code" gorm:"type:varchar(10);not null"`
	FirstName          string   `json:"firstName" example:"Ravi" gorm:"type:varchar(50)"`
	LastName           string   `json:"lastName" example:"Sharma" gorm:"type:varchar(50)"`
	Email              string   `json:"email" example:"john@doe.com" gorm:"type:varchar(100)"`
	Contact            string   `json:"contact" example:"1234567890" gorm:"type:varchar(15)"`
	AcademicYear       *uint8    `json:"academicYear" example:"1" gorm:"type:tinyint(2)"`
	Type               *uint8   `json:"talentType" example:"4" gorm:"type:tinyint(2)"`
	Resume             *string  `json:"resume" gorm:"type:varchar(200)"`
	ExperienceInMonths *uint    `json:"experienceInMonths"`
	Image              *string  `json:"image" gorm:"type:varchar(200)"`
	Gender             *string  `json:"gender" gorm:"type:varchar(50)"`
	DateOfBirth        *string  `json:"dateOfBirth" gorm:"type:date"`
}

I want to update one field at a time, so I am sending only one field in json to the API as a PATCH http request and in backend(Golang) I am converting the json to struct where in only that field in json will have value in the struct... all other fields will be nil.

For example I am sending firstName, now when I convert it to struct only the firstName field is filled. Now I want to validate that field.. like firstName is a compulsary field so it will have two validations.. one for checking if its empty and one for the max number of characters.

Like wise all fields have some validations. Now how do I validate only that particular field. Having switch cases is what I had considered but is there any other optimal way to do this in golang??

答案1

得分: 1

我遇到了相同的情况,并通过以下方式解决:

添加了一个GetJsonFields方法,用于将JSON键获取为字符串数组

type Book struct {
    Id           int    `json:"id"`
    Title        string `json:"title" validate:"required"`
    Descr        string `json:"description"`
    ThumbnailUrl string `json:"thumbnail_url" validate:"required"`
    CreatedAt    string `json:"created_at" validate:"required"`
}

func (b Book) GetJsonFields() []string {
    var jsonFields []string
    val := reflect.ValueOf(b)
    for i := 0; i < val.Type().NumField(); i++ {
        jsonFields = append(jsonFields, val.Type().Field(i).Tag.Get("json"))
    }
    return jsonFields
}

我还编写了一个小的辅助函数来检查字符串是否包含:

func contains(stringSlice []string, text string) bool {
    for _, a := range stringSlice {
        if a == text {
            return true
        }
    }
    return false
}

有了这些,编写简单的验证逻辑就很容易了:

// 获取URL参数id
book_id := mux.Vars(r)["id"]

// 解码请求体
var generic map[string]interface{}
json.NewDecoder(r.Body).Decode(&generic)

// 获取JSON字段
jsonFields := new(models.Book).GetJsonFields()

// 遍历请求体
// 如果有一个键不匹配 -> 返回http.StatusBadRequest
for k, _ := range generic {
    if contains(jsonFields, k) == false {
        rw.WriteHeader(http.StatusBadRequest)
        response := responses.BookResponse{Status: http.StatusBadRequest, Message: "error", Data: map[string]interface{}{"data": "提供的字段未知。"}}
        json.NewEncoder(rw).Encode(response)
        return
    }
}

以上是翻译好的内容,请查阅。

英文:

i come across the same situation and solved it this way:

added a GetJsonFields method to get the json keys in a string array

type Book struct {
	Id           int    `json:&quot;id&quot;`
	Title        string `json:&quot;title&quot; validate:&quot;required&quot;`
	Descr        string `json:&quot;description&quot;`
	ThumbnailUrl string `json:&quot;thumbnail_url&quot; validate:&quot;required&quot;`
	CreatedAt    string `json:&quot;created_at&quot; validate:&quot;required&quot;`
}

func (b Book) GetJsonFields() []string
 {
	var jsonFields []string
	val := reflect.ValueOf(b)
	for i := 0; i &lt; val.Type().NumField(); i++ {
		jsonFields = append(jsonFields, val.Type().Field(i).Tag.Get(&quot;json&quot;))

	}

	return jsonFields
}

i also wrote a small helper function to check for the string to contain:

func contains(stringSlice []string, text string) bool {
	for _, a := range stringSlice {
		if a == text {
			return true
		}
	}
	return false
}

With that it is easy to write a simple validation logic

        // get url param id
		book_id := mux.Vars(r)[&quot;id&quot;]

		// decode body
		var generic map[string]interface{}
		json.NewDecoder(r.Body).Decode(&amp;generic)

		// get json fields
		jsonFields := new(models.Book).GetJsonFields()

		// loop through the body
		// if one key does not match -&gt; return http.StatusBadRequest
		for k, _ := range generic {
			if contains(jsonFields, k) == false {
				rw.WriteHeader(http.StatusBadRequest)
				response := responses.BookResponse{Status: http.StatusBadRequest, Message: &quot;error&quot;, Data: map[string]interface{}{&quot;data&quot;: &quot;a provided field is unknown.&quot;}}
				json.NewEncoder(rw).Encode(response)
				return
			}
		}

huangapple
  • 本文由 发表于 2022年7月18日 18:44:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/73021065.html
匿名

发表评论

匿名网友

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

确定