如何在GO中验证实体?

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

How to validate entities in GO?

问题

在Go语言中如何进行验证?

互联网上的所有结果都建议我使用github.com/go-playground/validator/v10

但是问题是,每当我将结构体传递给另一个层或函数时,为了确保其有效性,我必须一遍又一遍地调用validator.Struct()

我考虑直接在结构体中进行验证(这是我通常在C#中做的方式),为此我为结构体创建了一个构造函数,将所有字段设为私有,并使用getter和setter(验证逻辑将在setter和构造函数中),但问题是我无法使用gorm或mongodb将实体映射到表,因为所有字段都是私有的,这些库无法读取私有字段,但如果我不将它们设为私有,我可能会意外地创建一个没有使用构造函数setter的结构体。

你在Go语言中如何处理实体验证?

英文:

How to validate in GO?

all results on the internet suggest me to use github.com/go-playground/validator/v10

but the problem whenever I pass the struct to another layer or functions, to make sure it is valid, I have to call validator.Struct() again and again.

I think about validate directly in the struct (that the way I usually do in c#), to implement it I create a constructor for the struct, make all fields private and using getter and setter (the validation logic will be inside the setter and constructor), but the problem is I can not use gorm or mongodb to map entity to table, because all the fields are private and those libs can not read private fields, but if I don't make them private, I can accidently create an struct without using constructor or setter

how do you deal with entity validation in GO?

答案1

得分: 1

你可以将结构体设为私有,但是将其字段导出。这样,人们需要使用该私有结构体的导出构造函数来获取其实例。

例如,你有一个名为store的包,定义了一个未导出的结构体类型,并创建了一个导出的构造函数。

package store

type foo struct { Name string }

func NewFoo(name string) foo { return foo{name} }

这样,你的包的用户需要调用构造函数来获取结构体的实例。

package main

import "myorg.com/app/store"

func main() {
  f := store.NewFoo("gopher")
  fmt.Println(f.Name)
}

这并不是百分之百可靠的,因为你仍然可以在store包内部出错,而且在调用构造函数后,结构体的用户也可以更改名称。

如果你还想通过setter强制执行验证,可能无法避免使用某种辅助结构体。


依我之见:

也许你的想法过于保守了。我通常对验证用户输入感到满意。在我的程序中,我不会不断地进行自我验证。

另一个需要考虑的因素是,你可能希望使用抽象和松耦合。例如,具有gorm特定标签的结构体可能只为存储层所知,而不会在整个应用程序中传递。在这种情况下,你的验证可以放在store.CreateUser()或类似的函数中。也许它还可以接受上述提到的辅助结构体。

英文:

You could make the struct private, but have its fields exported. That way, people need to call the exported constructor of the package with that private struct, to get an instance of it.

For example, you have a store package that defines the struct type, but unexported. Additionally, you create an exported constructor.

package store

type foo struct { Name string }

func NewFoo(name string) foo { return foo{name} }

That way, users of your package, need to call the constructor to get an instance of the struct.

package main

import "myorg.com/app/store"

func main() {
  f := store.NewFoo("gopher")
  fmt.Println(f.Name)
}

This is not 100% foolproof, as you still can mess up within that store package, and also users of your struct can change the name after calling the constructor.

If you also want to enforce validation via setter, you probably don't get around some kind of helper struct.


In my opinion:

Perhaps your idea is too defensive. I am usually fine with validating user input. Within my program, I am not constantly validating myself.

Another thing to consider is that you probably want abstractions and loose coupling. For example, a struct with gorm specific tags, may only be known to your storage layer and not get passed around the entire app. In that sense, your validation could go into store.CreateUser() or similar. Perhaps it could also take such a helper struct as mentioned above.

答案2

得分: 0

如果你想在不使用GoValidator的情况下进行结构体验证,你可以构建自己的自定义验证。请查看下面的代码:

1 - 使用私有字段和验证标签定义你的结构体:

type MyStruct struct {
    field1 string `validate:"required"`
    field2 int    `validate:"gte=0"`
}

2 - 为每个字段创建getter和setter方法:

func (s *MyStruct) GetField1() string {
    return s.field1
}

func (s *MyStruct) SetField1(value string) error {
    // 使用你自己的验证逻辑或验证库验证值
    if len(value) == 0 {
        return errors.New("field1 is required")
    }

    // 如果通过验证,设置值
    s.field1 = value
    return nil
}

func (s *MyStruct) GetField2() int {
    return s.field2
}

func (s *MyStruct) SetField2(value int) error {
    // 使用你自己的验证逻辑或验证库验证值
    if value < 0 {
        return errors.New("field2 must be greater than or equal to 0")
    }

    // 如果通过验证,设置值
    s.field2 = value
    return nil
}

3 - 在代码中使用这些getter和setter方法来访问和修改结构体字段。这样可以确保在设置值时始终应用验证逻辑。

obj := MyStruct{}
err := obj.SetField1("value1")
if err != nil {
    // 处理验证错误
}

err = obj.SetField2(10)
if err != nil {
    // 处理验证错误
}

// 访问字段值
value1 := obj.GetField1()
value2 := obj.GetField2()
英文:

If you want to use struct validation without using GoValidator you can build your own custom validation. Check the code below:

1 - Define your struct with private fields and validation tags:

type MyStruct struct {
    field1 string `validate:&quot;required&quot;`
    field2 int    `validate:&quot;gte=0&quot;`
}

2- Create getter and setter methods for each field:

func (s *MyStruct) GetField1() string {
    return s.field1
}

func (s *MyStruct) SetField1(value string) error {
    // Validate the value using your custom validation logic or a validation library
    if len(value) == 0 {
        return errors.New(&quot;field1 is required&quot;)
    }

    // Set the value if it passes validation
    s.field1 = value
    return nil
}

func (s *MyStruct) GetField2() int {
    return s.field2
}

func (s *MyStruct) SetField2(value int) error {
    // Validate the value using your custom validation logic or a validation library
    if value &lt; 0 {
        return errors.New(&quot;field2 must be greater than or equal to 0&quot;)
    }

    // Set the value if it passes validation
    s.field2 = value
    return nil
}

3- Use these getter and setter methods throughout your code to access and modify the struct fields. This ensures that validation logic is always applied when setting values.

obj := MyStruct{}
err := obj.SetField1(&quot;value1&quot;)
if err != nil {
    // Handle validation error
}

err = obj.SetField2(10)
if err != nil {
    // Handle validation error
}

// Access field values
value1 := obj.GetField1()
value2 := obj.GetField2()

huangapple
  • 本文由 发表于 2023年6月10日 16:30:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76445397.html
匿名

发表评论

匿名网友

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

确定