Files
go-simple-api/internal/config/config.go
T
2026-07-16 10:13:46 +03:30

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
}