Golang 识别并验证设置为 null 或未提供的 json 值

Golang identify and validate json value set to null or not provided

提问人:osflw 提问时间:8/25/2023 最后编辑:osflw 更新时间:8/28/2023 访问量:228

问:

我有接受 PATCH 方法并更新给定字段的 API。 具有以下正文的 PATCH 请求会更改用户的年龄。

{
   "age": 10
}

我在处理价值方面遇到了问题。 我的结构如下:nullUser

type User struct {
    Name string
    Age int
    Schedule *schedule
}

type Schedule struct {
    time int
    weekdays []int
}

若要删除用户的计划字段,请求正文应如下所示:

{
    "schedule": null
}

然后,我必须确定是否提供了 null 值,这在上述定义中是不可能的。 我编写了有助于识别它的新结构(https://www.calhoun.io/how-to-determine-if-a-json-key-has-been-set-to-null-or-not-provided/):

type User struct {
    Name 
    Age int
    Schedule Optional[Schedule]
}

type Optional[T any] struct {
    Value   *T
    Defined bool
}

func (t *Optional[T]) UnmarshalJSON(data []byte) error {
    t.Defined = true
    return json.Unmarshal(data, &t.Value)
}

func (t *Optional[T]) IsNullDefined() bool {
    return t.Defined && t.Value == nil
}

func (t *Optional[T]) HasValue() bool {
    return t.Defined && t.Value != nil
}

而且,现在我有一个问题,即行动是不同的

{
    "age": null
}

这将被忽略,并且

{
    "schedule": null
}

这将删除计划。

我该如何处理和防止其他类型的值,这应该是类型错误?null


编辑:

用一句话来说,我想拒绝除可选结构之外的所有给定值字段(不是未提供的字段)。您可以向我建议任何其他解决问题的解决方案。null

JSON Go 验证

评论

1赞 mkopriva 8/25/2023
定义一个类似于 的类型,并让新类型将传递的 to 与 进行比较,即 ,如果 ,则可以返回一个错误。例如,您可以调用 new 类型。Optional[T]dataUnmarshalJSONnullif string(data) == "null" {trueUnmarshalJSONRequired[T]
0赞 osflw 8/25/2023
@mkopriva 谢谢你的新想法。使用您的解决方案,我必须放入除字段之外的所有字段。我认为应该被拒绝,因为它是整数类型并且不能为空。可能吗?RequiredOptional"age": nullage
1赞 mkopriva 8/25/2023
不,这是不可能的,不是标准库的.请参见 json。Unmarshal:“JSON null 值通过将 Go 值设置为 nil 来解组到接口、映射、指针或切片中。由于 null 在 JSON 中通常用于表示“不存在”,因此将 JSON null 解组为任何其他 Go 类型对值没有影响,也不会产生错误encoding/json
0赞 osflw 8/25/2023
@mkopriva 那么我是否应该更改我的 API 规范以实现删除计划?
0赞 Volker 8/25/2023
您的 API (JSON) 不应依赖于对象中缺少的计划与计划为 null。

答:

0赞 Saurabh Prakash 8/25/2023 #1

尝试将 Age 设为 *int 类型。

尝试创建 an 类型。https://go.dev/play/p/f56pdESOEt7AgeOptional[int]

评论

0赞 osflw 8/25/2023
它不能解决问题。 也忽略 .即,给出“无法识别”字段。*int"age": nullage
0赞 Saurabh Prakash 8/25/2023
@osflw 检查更新的答案。
0赞 osflw 8/25/2023
谢谢。它解决了这个问题,但我想要的是通用解决方案,即在语言方面进行类型验证。有了解决方案,如果我想拒绝,我必须把我所有的字段和代码都检查有效。我认为这不是一个好主意。nullOptional
0赞 Saurabh Prakash 8/25/2023
@osflw你到底需要做什么?您需要识别以下所有 3 种情况,对吧?1. 有效 2.空 3. 未提供。使用指针,您将只能获得 3 个选项中的 2 个。没有自定义结构是不可能的ageageage
0赞 osflw 8/25/2023
是的,但默认情况下,它拒绝所有给定的值。因此,只有字段可以接受和删除该字段。nullOptionalnull
-1赞 osflw 8/28/2023 #2

从@Volker找到解决方案并发布自我回答:

上述问题使用 Merge Patch JSON (rfc7396)。它有一个图书馆。

https://pkg.go.dev/github.com/evanphx/json-patch/v5#MergePatch

我拉取 GET 结果并合并 GET 结果和 json 补丁体。然后,您可以注意到哪些值被取消了。