88 lines
3.1 KiB
Go
88 lines
3.1 KiB
Go
// Package config is responsible for one thing only: reading configuration
|
|||
|
|
// from environment variables and handing back a single, typed Config struct
|
||
|
|
// that the rest of the app can use.
|
||
|
|
//
|
||
|
|
// Why centralize this instead of calling os.Getenv() all over the codebase?
|
||
|
|
// - One place to see every setting the app needs.
|
||
|
|
// - One place to define sane defaults for local development.
|
||
|
|
// - Easy to swap the *source* later (e.g. read from a file, from Vault,
|
||
|
|
// from AWS Secrets Manager) without touching any other package.
|
||
|
|
package config
|
||
|
|
|
||
|
|
import (
|
||
|
|
"os"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Config holds every piece of runtime configuration the application needs.
|
||
|
|
// It is built once, in main(), and then passed down (by value - it's a
|
||
|
|
// small, read-only struct) into whichever package needs it: the router,
|
||
|
|
// the database connector, the session manager, the OAuth config, etc.
|
||
|
|
type Config struct {
|
||
|
|
// Port is the TCP port the HTTP server listens on.
|
||
|
|
Port string
|
||
|
|
// Env distinguishes "development" from "production". Currently used
|
||
|
|
// to decide whether the session cookie requires HTTPS (Secure flag).
|
||
|
|
Env string
|
||
|
|
|
||
|
|
// --- MySQL connection settings ---
|
||
|
|
DBHost string
|
||
|
|
DBPort string
|
||
|
|
DBUser string
|
||
|
|
DBPassword string
|
||
|
|
DBName string
|
||
|
|
|
||
|
|
// --- Redis connection settings (used for session storage) ---
|
||
|
|
RedisAddr string
|
||
|
|
|
||
|
|
// --- Google OAuth2 settings ---
|
||
|
|
GoogleClientID string
|
||
|
|
GoogleClientSecret string
|
||
|
|
GoogleRedirectURL string
|
||
|
|
|
||
|
|
// AllowedOrigins is the CORS allowlist: which frontend origins are
|
||
|
|
// permitted to call this API from browser JavaScript.
|
||
|
|
AllowedOrigins []string
|
||
|
|
}
|
||
|
|
|
||
|
|
// Load reads every setting from the process environment, falling back to
|
||
|
|
// sensible local-development defaults when a variable isn't set. In
|
||
|
|
// production you would set all of these explicitly (e.g. via
|
||
|
|
// docker-compose "environment:", a systemd unit, or your orchestrator's
|
||
|
|
// secret/config mechanism) rather than relying on the defaults.
|
||
|
|
func Load() Config {
|
||
|
|
return Config{
|
||
|
|
Port: getEnv("PORT", "8080"),
|
||
|
|
Env: getEnv("ENV", "development"),
|
||
|
|
|
||
|
|
DBHost: getEnv("DB_HOST", "127.0.0.1"),
|
||
|
|
DBPort: getEnv("DB_PORT", "3306"),
|
||
|
|
DBUser: getEnv("DB_USER", "root"),
|
||
|
|
DBPassword: getEnv("DB_PASSWORD", "devpass"),
|
||
|
|
DBName: getEnv("DB_NAME", "go_simple_api"),
|
||
|
|
|
||
|
|
RedisAddr: getEnv("REDIS_ADDR", "127.0.0.1:6379"),
|
||
|
|
|
||
|
|
GoogleClientID: getEnv("GOOGLE_CLIENT_ID", ""),
|
||
|
|
GoogleClientSecret: getEnv("GOOGLE_CLIENT_SECRET", ""),
|
||
|
|
GoogleRedirectURL: getEnv("GOOGLE_REDIRECT_URL", "http://localhost:8080/auth/google/callback"),
|
||
|
|
|
||
|
|
// ALLOWED_ORIGINS is a comma-separated list, e.g.:
|
||
|
|
// ALLOWED_ORIGINS=http://localhost:3000,https://myapp.com
|
||
|
|
// strings.Split on a single-value default still works fine and
|
||
|
|
// yields a one-element slice.
|
||
|
|
AllowedOrigins: strings.Split(getEnv("ALLOWED_ORIGINS", "http://localhost:3000"), ","),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// getEnv reads a single environment variable, returning fallback if it's
|
||
|
|
// unset or empty. It's unexported (lowercase) because nothing outside this
|
||
|
|
// package needs to read raw env vars directly - everyone else should go
|
||
|
|
// through the Config struct instead.
|
||
|
|
func getEnv(key, fallback string) string {
|
||
|
|
if v := os.Getenv(key); v != "" {
|
||
|
|
return v
|
||
|
|
}
|
||
|
|
return fallback
|
||
|
|
}
|