Golang结构验证:惯用方式
#编程 #go #validations #idiomatic

验证通常是所有编程语言中最常见的问题之一。
在我开始在Golang中解释如何进行惯用的方法之前...让我简要解释为什么我首先潜入其中。

在使用大量微服务的项目工作时,
需要维护每个人的构建时间配置。

这也意味着验证这些配置。否则,微服务将有运行时故障的风险! ðÖ

因此,假设我们在config.json中具有以下配置

{
  "server_url": "https://some-server-url",
  "app_port": 8080
}

然后可以将其封装在Golang结构中:

type Config struct {
    ServerUrl string `json:"server_url"`
    AppPort   int    `json:"app_port"`
}

我们将config.json加载到结构:

func LoadConfig() (*Config, error) {
    configFile, err := os.Open("configuration/config.json")
    if err != nil {
        log.Fatal("Could not open config file : ", err.Error())
    }

    decoder := json.NewDecoder(configFile)
    config := Config{}

    decodeErr := decoder.Decode(&config)
    if decodeErr != nil {
        log.Fatal("Could not decode config file : ", decodeErr.Error())
    }

    if !Validate(config) {
        return nil, errors.New("Invalid config !")
    }
    return &config, nil
}

现在,假设我们要验证:

  1. 服务器URL和端口是非空的
  2. 端口的值是数字,在8080和8085之间

现在,直截了当的方法是:

编写if-else条件代码以验证每个代码。就像是:

func Validate(config Config) bool {
    if config.ServerUrl == "" {
        return false
    }
    if config.AppPort == 0 {
        return false
    }
    if config.AppPort >= 8080 || config.AppPort <= 8085 {
        return false
    }
    return true
}

这可能会对更多此类字段和验证感到非常混乱。是的! ðµð«

一定有更好的方法(否则该博客将不存在!)

做到这一点的清洁剂,惯用的方法是使用 struct验证

type Config struct {
    ServerUrl string `json:"server_url" validate:"required"`
    AppPort   int    `json:"app_port" validate:"required,numeric,gte=8080,lte=8085"`
}    

声明性,更接近结构定义。那不是美丽!

现在,我们的验证功能看起来像这样:

func Validate(config Config) bool {
    validate := validator.New()
    err := validate.Struct(config)
    if err != nil {
        fmt.Println("Invalid config !", err.Error())
        return false
    }
    return true
}

此外,我们可能会有更有意义的错误来指出失败的验证:

func Validate(config Config) bool {
    validate := validator.New()
    err := validate.Struct(config)
    if err != nil {
        fmt.Println("Invalid config !")
        for _, validationErr := range err.(validator.ValidationErrors) {
            fmt.Println(validationErr.StructNamespace() + " violated " + validationErr.Tag() + " validation.")
        }
        return false
    }
    return true
}    

前往Awesome validator library获取更多此类标签...