我有一个 go 结构,用于实体的 POST
type Student struct {
ID string `json:"id" firestore:"id"`
Name string `json:"name" validate:"required" firestore:"name"`
}
从 POST 正文请求中,我可以将正文发送为
{
"id" : 123,
"name" : "Student Name"
}
我想实现一个功能,在进行验证时请求应该失败,并且不允许在 POST 正文中添加“id”字段。
由于我计划为 GET 重用相同的结构,所以我无法跳过 json 编组和解组中的“id”。
有没有像 allowed:true 或 false 这样的结构体标签?
我尝试跳过 json 验证,但我想重用相同的结构,但无法继续。
在代码逻辑中,我每次都可以将其重写为空值,但这似乎不是添加自定义逻辑以在转换为对象后更新字段的好方法。
看到了各种验证结构标记,但没有找到任何与用例匹配的
据我了解,适合您的各种解决方案之一是使用
len
valitor。多亏了它,您可以强制提供的结构不设置 ID
值。我看到在您的示例中, ID
被视为字符串,这意味着它的零值是 ""
。package main
import (
"encoding/json"
"fmt"
"github.com/go-playground/validator/v10"
)
type Student struct {
ID string `json:"id" validate:"len=0"`
Name string `json:"name" validate:"required"`
}
func main() {
validator := validator.New()
var student Student
studentOk := `{"id": "", "name": "John Doe"}`
err := json.Unmarshal([]byte(studentOk), &student)
if err != nil {
panic(err)
}
err = validator.Struct(student)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("fine")
}
studentIdNotProvided := `{"name": "John Doe"}`
err = json.Unmarshal([]byte(studentIdNotProvided), &student)
if err != nil {
panic(err)
}
err = validator.Struct(student)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("fine")
}
studentKo := `{"id": "123", "name": "John Doe"}`
err = json.Unmarshal([]byte(studentKo), &student)
if err != nil {
panic(err)
}
err = validator.Struct(student)
if err != nil {
fmt.Println(err)
}
}
您可能面临的每一种可能的情况都应该涵盖:
""
请小心,如果您将
视为整数,则必须将验证切换为ID
之类的内容,因为整数的零值是!= 0
。0
如果这能解决您的问题,请告诉我。
这是我更新的解决方案。我给你两种不同的方法:
下面,您可以找到完整的工作代码:
package main
import (
"encoding/json"
"fmt"
"time"
)
type Example struct {
ID string `json:"id"`
Name string `json:"name" validate:"required"`
Count int `json:"count"`
CreatedTime *time.Time `json:"created_time"`
UpdatedTime *time.Time `json:"updated_time,omitempty"`
DeletedTime *time.Time `json:"deleted_time,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
}
type ExamplePost struct {
Name string `json:"name" validate:"required"`
}
func main() {
jsonReq := `{"ID":"123","Name":"John Doe","Count":1,"created_time":"2022-11-07 16:52:41.196032353 +0100","updated_time":"2022-11-07 16:52:41.196032353 +0100","deleted_time":"2022-11-07 16:52:41.196032353 +0100","expires_at":"2022-11-07 16:52:41.196032353 +0100"}`
fmt.Println("first approach: with a tiny struct")
var examplePost ExamplePost
err := json.Unmarshal([]byte(jsonReq), &examplePost)
if err != nil {
panic(err)
}
fmt.Printf("name: %q\n", examplePost.Name)
postMap := make(map[string]interface{}, 0)
err = json.Unmarshal([]byte(jsonReq), &postMap)
if err != nil {
panic(err)
}
fmt.Println("second approach: with a map")
var example Example
for k, v := range postMap {
if k == "Name" {
if name, ok := v.(string); ok {
example.Name = name
} else {
example.Name = ""
}
}
}
fmt.Printf("name: %q\n", example.Name)
}
第二种方法需要更多的努力,因为您必须解组传入的 JSON 请求,循环遍历其键和值,选择相关的键和值,键入转换值以确保格式正确,最后分配给您的结构。
希望这能解决您的问题。
对于简单的 POST 正文,您可以使用这个包。它非常小,但支持所有基本内容(必需、最小/最大、选择、内部结构验证等)。最重要的是,它使用起来也很简单。
您只需使用您允许的值定义一个结构:
type Object struct {
ID *string `validations:"type=string;required=true`
Code *int `validations:"type=int;choices=1,2,3`
Person *Person `validations:"type=struct`
Owners []string `validations:"type=[]string`
PersonList []Person `validations:"type=[]struct`
}
然后你只需要:
form := new(Object)
validationErrors := jsonValidator.Validate(c.Body(), form)
表格将被填充!