英文:
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:"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
}
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)["id"]
// decode body
var generic map[string]interface{}
json.NewDecoder(r.Body).Decode(&generic)
// get json fields
jsonFields := new(models.Book).GetJsonFields()
// loop through the body
// if one key does not match -> return 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": "a provided field is unknown."}}
json.NewEncoder(rw).Encode(response)
return
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论