package config import ( "net" "net/url" "os" "strconv" "github.com/joho/godotenv" ) type Config struct { Addr string GinMode string DB DBConfig } type DBConfig struct { Host string Port string User string Password string Name string SSLMode string MaxConns int32 AppName string } func Load() Config { _ = godotenv.Load() cfg := Config{ Addr: getenv("ADDR", ":8082"), GinMode: getenv("GIN_MODE", "release"), DB: DBConfig{ Host: must("PGHOST"), Port: must("POSTGRES_PORT"), User: must("POSTGRES_USER"), Password: os.Getenv("POSTGRES_PASSWORD"), Name: must("POSTGRES_DB"), SSLMode: getenv("PGSSLMODE", "disable"), AppName: getenv("DB_APP_NAME", "current-api"), }, } if n := getenv("DB_MAX_CONNS", ""); n != "" { if v, err := strconv.Atoi(n); err == nil && v > 0 { cfg.DB.MaxConns = int32(v) } } return cfg } func (d DBConfig) DSN() string { // DATABASE_URL wins if present if raw := os.Getenv("DATABASE_URL"); raw != "" { return raw } u := &url.URL{ Scheme: "postgres", User: url.UserPassword(d.User, d.Password), Host: net.JoinHostPort(d.Host, d.Port), Path: "/" + d.Name, } q := url.Values{} q.Set("sslmode", d.SSLMode) if d.AppName != "" { q.Set("application_name", d.AppName) } u.RawQuery = q.Encode() return u.String() } func RedactDSN(raw string) string { u, err := url.Parse(raw) if err != nil || u.User == nil { return raw } if _, ok := u.User.Password(); ok { u.User = url.UserPassword(u.User.Username(), "*****") } return u.String() } func getenv(k, def string) string { if v := os.Getenv(k); v != "" { return v } return def } func must(k string) string { v := os.Getenv(k) if v == "" { panic("missing required env: " + k) } return v }