如何在go验证中验证json正文中允许的字段

问题描述 投票:0回答:3

我有一个 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 验证,但我想重用相同的结构,但无法继续。

在代码逻辑中,我每次都可以将其重写为空值,但这似乎不是添加自定义逻辑以在转换为对象后更新字段的好方法。

看到了各种验证结构标记,但没有找到任何与用例匹配的

validation go request-validation go-playground
3个回答
0
投票

据我了解,适合您的各种解决方案之一是使用

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)
    }
}

您可能面临的每一种可能的情况都应该涵盖:

  1. ID 设置为
    ""
  2. 的 JSON 请求
  3. 根本未提供 ID 的 JSON 请求
  4. 指定 ID 的错误 JSON 请求

请小心,如果您将

ID
视为整数,则必须将验证切换为
!= 0
之类的内容,因为整数的零值是
0

如果这能解决您的问题,请告诉我。


0
投票

这是我更新的解决方案。我给你两种不同的方法:

  1. 创建一个小型结构,仅包含您想要从输入请求中获得的相关字段(首选方法
  2. 解组到地图上并仅分配与您相关的字段

下面,您可以找到完整的工作代码:

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 请求,循环遍历其键和值,选择相关的键和值,键入转换值以确保格式正确,最后分配给您的结构。
希望这能解决您的问题。


0
投票

对于简单的 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)

表格将被填充!

© www.soinside.com 2019 - 2024. All rights reserved.