68 lines
1.8 KiB
Go
68 lines
1.8 KiB
Go
|
package config
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/spf13/viper"
|
||
|
)
|
||
|
|
||
|
// Config holds all configuration for the application.
|
||
|
type Config struct {
|
||
|
Database DatabaseConfig `mapstructure:"database"`
|
||
|
Server ServerConfig `mapstructure:"server"`
|
||
|
}
|
||
|
|
||
|
// DatabaseConfig holds database connection configuration.
|
||
|
type DatabaseConfig struct {
|
||
|
User string `mapstructure:"user"`
|
||
|
Password string `mapstructure:"password"`
|
||
|
Dbname string `mapstructure:"dbname"`
|
||
|
Host string `mapstructure:"host"`
|
||
|
Port int `mapstructure:"port"`
|
||
|
Sslmode string `mapstructure:"sslmode"`
|
||
|
}
|
||
|
|
||
|
// ServerConfig holds server-specific configuration.
|
||
|
type ServerConfig struct {
|
||
|
Address string `mapstructure:"address"`
|
||
|
}
|
||
|
|
||
|
// Load reads configuration from file and environment variables.
|
||
|
func Load() (*Config, error) {
|
||
|
// 0. Configuration for environment variables
|
||
|
viper.SetEnvPrefix("APP") // Variables must start with "APP_" (e.g., APP_SERVER_ADDRESS)
|
||
|
|
||
|
// 1. Base configuration file
|
||
|
viper.SetConfigName("config") // config.yaml
|
||
|
viper.SetConfigType("yaml")
|
||
|
viper.AddConfigPath(".")
|
||
|
|
||
|
// Read the base file. Don't stop if it's not found.
|
||
|
if err := viper.ReadInConfig(); err != nil {
|
||
|
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||
|
return nil, fmt.Errorf("error reading base config file config.yaml: %w", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 2. Override with environment-specific file (via APP_ENV)
|
||
|
if env := os.Getenv("APP_ENV"); env != "" {
|
||
|
viper.SetConfigName("config." + env) // e.g., config.prod.yaml
|
||
|
if err := viper.MergeInConfig(); err != nil {
|
||
|
log.Printf("Warning: could not load config file for environment '%s': %v", env, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||
|
viper.AutomaticEnv()
|
||
|
|
||
|
var cfg Config
|
||
|
if err := viper.Unmarshal(&cfg); err != nil {
|
||
|
return nil, fmt.Errorf("unable to decode config into struct: %w", err)
|
||
|
}
|
||
|
|
||
|
return &cfg, nil
|
||
|
}
|