Skip to content

Config Validation

Validate a config struct at startup so the program fails fast instead of trickling NPEs hours later.

go
package main

import (
    "fmt"
    "log"

    "github.com/wuhan005/govalid"
)

type Database struct {
    Host     string `valid:"required" label:"数据库地址"`
    Port     int    `valid:"required;min:1;max:65535" label:"端口"`
    Username string `valid:"required" label:"用户"`
    Password string `valid:"required" label:"密码"`
    SSLMode  string `valid:"list:disable,allow,prefer,require" label:"SSL 模式"`
}

type HTTPServer struct {
    Listen string `valid:"required" label:"监听地址"`
    Port   int    `valid:"min:1;max:65535" label:"HTTP 端口"`
}

type Config struct {
    Env      string   `valid:"required;list:dev,staging,production" label:"环境"`
    Database Database
    HTTP     HTTPServer
    Admins   []string `valid:"required;minlen:1" label:"管理员邮箱"`
}

func loadAndValidate() (*Config, error) {
    cfg := &Config{
        Env: "production",
        Database: Database{
            Host:     "db.internal",
            Port:     5432,
            Username: "app",
            SSLMode:  "require",
        },
        HTTP: HTTPServer{Listen: "0.0.0.0", Port: 8080},
        Admins: []string{"ops@example.com"},
    }

    if errs, ok := govalid.Check(cfg); !ok {
        msg := "config invalid:\n"
        for _, e := range errs {
            msg += fmt.Sprintf("  - %s\n", e.Error())
        }
        return nil, fmt.Errorf(msg)
    }
    return cfg, nil
}

func main() {
    cfg, err := loadAndValidate()
    if err != nil {
        log.Fatal(err)
    }
    _ = cfg
}

Tips

  • Make Validate() your final gate for invariants that span sections, e.g. if cfg.Env == "production" && cfg.HTTP.Listen == "0.0.0.0".
  • Pair govalid with Viper / koanf / your loader of choice — load first, validate next. govalid only sees the final struct.
  • For a single-pass dev experience, treat any error from loadAndValidate as fatal so the binary never starts in a half-baked state.

Released under the MIT License.