Configuration loading
pkg/config owns Env, LoadEnv, and legacy typed environment helpers. Startup calls LoadEnv once; it reads a default/explicit dotenv file, gives process environment precedence (even empty values), applies defaults for absent values, and returns malformed-file/numeric errors. It leaves process environment unchanged.
DATABASE_URL and JWT_SECRET default to empty and are checked by consumers. Identity validates JWT minimum secret length and maximum lifetimes; API startup verifies database connectivity. Configuration includes Redis values that are not yet used by startup.
GetEnv, GetEnvAsInt, and GetEnvAsBool are legacy helpers with different empty-value/fallback behavior. Prefer LoadEnv for application startup and explicit typed configuration for dependencies. See configuration settings and the tested example below.
package config_test
import (
"fmt"
"os"
"github.com/prescriptoo/prescriptoo-api/pkg/config"
)
// LoadEnv accepts an explicit file, so tools can choose configuration without
// depending on the process working directory. Environment values take priority.
func ExampleLoadEnv() {
// Fix values used by this example, restoring the caller's environment after it.
for key, value := range map[string]string{
"PORT": "9090", "JWT_EXPIRATION_HOURS": "1", "REFRESH_TOKEN_EXPIRATION_DAYS": "7",
} {
previous, exists := os.LookupEnv(key)
defer func() {
if exists {
_ = os.Setenv(key, previous)
} else {
_ = os.Unsetenv(key)
}
}()
if err := os.Setenv(key, value); err != nil {
panic(err)
}
}
file, err := os.CreateTemp("", "prescriptoo-config-*.env")
if err != nil {
panic(err)
}
defer func() {
if err := os.Remove(file.Name()); err != nil {
panic(err)
}
}()
if _, err := file.WriteString("DATABASE_URL=postgres://localhost/example\nPORT=8088\n"); err != nil {
panic(err)
}
if err := file.Close(); err != nil {
panic(err)
}
env, err := config.LoadEnv(file.Name())
if err != nil {
panic(err)
}
fmt.Println("Port:", env.Port)
fmt.Println("Access lifetime:", env.JWTExpirationHours)
// Output:
// Port: 9090
// Access lifetime: 1
}Tests cover precedence, explicitly empty values, missing default/explicit files, invalid numeric input, and lack of environment mutation.
Code reference
See the generated config package.