Мультиформатная конфигурация
Библиотека env поддерживает три формата конфигурации: .env, JSON и YAML с автоматическим определением формата при загрузке.
Определение формата
Правила автоматического определения
| Расширение | Формат | Константа |
|---|---|---|
.env | Формат .env | FormatEnv |
.json | JSON | FormatJSON |
.yaml, .yml | YAML | FormatYAML |
| Другое | Авто | FormatAuto |
Функция DetectFormat
format := env.DetectFormat("config.json") // FormatJSON
format = env.DetectFormat("settings.yaml") // FormatYAML
format = env.DetectFormat("app.yml") // FormatYAML
format = env.DetectFormat(".env") // FormatEnv
format = env.DetectFormat("unknown") // FormatAuto
fmt.Println(format.String()) // "json", "yaml", "dotenv", "auto"Загрузка файлов нескольких форматов
Один формат
loader.LoadFiles("config.env")
loader.LoadFiles("settings.json")
loader.LoadFiles("secrets.yaml")Смешанные форматы
// Автоматическое определение формата каждого файла
loader.LoadFiles("config.env", "settings.json", "secrets.yaml")Порядок перекрытия
Загруженные позже файлы перекрывают загруженные ранее:
// Порядок: base -> env -> json -> yaml
loader.LoadFiles(
".env", // Базовая конфигурация
"config.json", // Перекрывает .env
"secrets.yaml", // Перекрывает config.json
)Формат JSON
Структура файла
{
"APP_NAME": "myapp",
"APP_PORT": "8080",
"DEBUG": "true",
"DATABASE": {
"HOST": "localhost",
"PORT": "5432"
}
}Примечание
Вложенные объекты будут преобразованы в плоский вид: DATABASE_HOST, DATABASE_PORT.
Разрешение имён ключей
Вложенные структуры JSON/YAML преобразуются в плоское хранилище. Библиотека поддерживает несколько способов доступа к ключам:
loader.LoadFiles("config.json")
// JSON: {"database": {"host": "localhost", "port": 5432}}
// Хранится как: DATABASE_HOST=localhost, DATABASE_PORT=5432
// Способ 1: Плоские ключи (рекомендуется)
host := loader.GetString("DATABASE_HOST") // localhost
port := loader.GetInt("DATABASE_PORT") // 5432
// Способ 2: Путь через точку (автопреобразование)
host := loader.GetString("database.host") // localhost
port := loader.GetInt("database.port") // 5432
// Способ 3: Верхний регистр с точкой
host := loader.GetString("DATABASE.HOST") // localhostПравила разрешения:
| Входной ключ | Преобразуется в |
|---|---|
"DATABASE_HOST" | "DATABASE_HOST" (точное совпадение) |
"database.host" | "DATABASE_HOST" (точка в подчёркивание) |
"app.config.name" | "APP_CONFIG_NAME" |
"servers.0.host" | "SERVERS_0_HOST" (индекс массива) |
Рекомендуемое использование
- В коде используйте плоские ключи:
GetString("DATABASE_HOST")- явно и эффективно - В конфигурационных файлах - читаемые пути: JSON/YAML используют естественную вложенную структуру
Правила преобразования в плоский вид:
| JSON-путь | Ключ хранения |
|---|---|
database.host | DATABASE_HOST |
database.port | DATABASE_PORT |
app.server.name | APP_SERVER_NAME |
servers.0.host | SERVERS_0_HOST |
Доступ к массивам
Массивы JSON преобразуются в ключи с индексом:
{
"servers": [
{ "host": "server1.example.com", "port": 8080 },
{ "host": "server2.example.com", "port": 8081 }
]
}// Доступ к элементам массива через плоские ключи
host0 := loader.GetString("SERVERS_0_HOST") // server1.example.com
port0 := loader.GetInt("SERVERS_0_PORT") // 8080
host1 := loader.GetString("SERVERS_1_HOST") // server2.example.com
// Получение всех хостов через цикл
var hosts []string
for i := 0; ; i++ {
h := loader.GetString(fmt.Sprintf("SERVERS_%d_HOST", i))
if h == "" {
break
}
hosts = append(hosts, h)
}
// hosts = ["server1.example.com", "server2.example.com"]Конфигурация парсинга JSON
cfg := env.DefaultConfig()
// Значение null преобразуется в пустую строку (по умолчанию true)
cfg.JSONNullAsEmpty = true
// Числа преобразуются в строки (по умолчанию true)
cfg.JSONNumberAsString = true
// Логические значения преобразуются в строки (по умолчанию true)
cfg.JSONBoolAsString = true
// Максимальная глубина вложенности (по умолчанию 10)
cfg.JSONMaxDepth = 20Примеры преобразования типов
{
"PORT": 8080,
"DEBUG": true,
"TIMEOUT": 30,
"RATES": [0.1, 0.2, 0.3]
}// JSONNumberAsString = true (по умолчанию)
port := loader.GetString("PORT") // "8080" (строка)
port := loader.GetInt("PORT") // 8080 (целое)
// JSONBoolAsString = true (по умолчанию)
debug := loader.GetString("DEBUG") // "true" (строка)
debug := loader.GetBool("DEBUG") // true (логическое)Формат YAML
Структура файла
# Конфигурация приложения
APP_NAME: myapp
APP_PORT: "8080"
DEBUG: true
# Конфигурация базы данных
DATABASE:
HOST: localhost
PORT: "5432"
USER: postgres
PASSWORD: secret
# Значения списков
ALLOWED_HOSTS:
- localhost
- example.comРазрешение имён ключей
Вложенные структуры YAML используют те же правила преобразования в плоский вид, что и JSON:
loader.LoadFiles("config.yaml")
// Доступ через плоские ключи
host := loader.GetString("DATABASE_HOST") // localhost
user := loader.GetString("DATABASE_USER") // postgresДоступ к массивам
Списки YAML преобразуются в ключи с индексом:
servers:
- host: server1.example.com
port: 8080
- host: server2.example.com
port: 8081// Доступ через плоские ключи
host0 := loader.GetString("SERVERS_0_HOST") // server1.example.com
port0 := loader.GetInt("SERVERS_0_PORT") // 8080
host1 := loader.GetString("SERVERS_1_HOST") // server2.example.com
// Получение всего списка
hosts := env.GetSliceFrom[string](loader, "ALLOWED_HOSTS") // ["localhost", "example.com"]Конфигурация парсинга YAML
cfg := env.DefaultConfig()
// Значение null/~ преобразуется в пустую строку (по умолчанию true)
cfg.YAMLNullAsEmpty = true
// Числа преобразуются в строки (по умолчанию true)
cfg.YAMLNumberAsString = true
// Логические значения преобразуются в строки (по умолчанию true)
cfg.YAMLBoolAsString = true
// Максимальная глубина вложенности (по умолчанию 10)
cfg.YAMLMaxDepth = 15Примеры преобразования типов
PORT: 8080
DEBUG: true
TIMEOUT: 30
RATES:
- 0.1
- 0.2
- 0.3// YAMLNumberAsString = true (по умолчанию)
port := loader.GetString("PORT") // "8080" (строка)
port := loader.GetInt("PORT") // 8080 (целое)
// YAMLBoolAsString = true (по умолчанию)
debug := loader.GetString("DEBUG") // "true" (строка)
debug := loader.GetBool("DEBUG") // true (логическое)
// Доступ к списку
rates := env.GetSliceFrom[float64](loader, "RATES") // [0.1, 0.2, 0.3]Формат .env
Структура файла
# Комментарии
APP_NAME=myapp
APP_PORT=8080
DEBUG=true
# Кавычки
MESSAGE="Hello World"
LITERAL='literal ${noexpand}'
# Подстановка переменных
BASE_URL=https://api.example.com
API_URL=${BASE_URL}/v1
# Значения по умолчанию
LOG_LEVEL=infoПодстановка переменных
cfg := env.DefaultConfig()
cfg.ExpandVariables = true // Включено по умолчанию
loader, _ := env.New(cfg)
loader.LoadFiles(".env")
// Содержимое .env:
// BASE_URL=https://api.example.com
// API_URL=${BASE_URL}/v1
apiURL := loader.GetString("API_URL")
// Вывод: https://api.example.com/v1Синтаксис подстановки
| Синтаксис | Описание |
|---|---|
${VAR} | Ссылка на переменную |
${VAR:-default} | Использовать значение по умолчанию, если переменная не существует |
# Примеры подстановки
HOST=localhost
PORT=8080
# Ссылка на другие переменные
URL=http://${HOST}:${PORT}
# Значения по умолчанию
TIMEOUT_VALUE=${TIMEOUT:-30s}
DEBUG_VALUE=${DEBUG:-false}Синтаксис export
# Поддержка префикса export (когда AllowExportPrefix = true)
export DATABASE_HOST=localhost
export DATABASE_PORT=5432Синтаксис в стиле YAML
cfg := env.DefaultConfig()
cfg.AllowYamlSyntax = true // Включить YAML-стиль# Поддержка пар ключ-значение в стиле YAML
KEY: value
ANOTHER_KEY: "quoted value"Паттерны смешанной конфигурации
Разделение разработки/продакшена
config/
├── base.json # Базовая конфигурация
├── development.env # Переопределения для разработки
├── production.yaml # Переопределения для продакшена
└── local.env # Локальные переопределения (не коммитить)func loadConfig(loader *env.Loader) error {
// 1. Базовая конфигурация
if err := loader.LoadFiles("config/base.json"); err != nil {
return err
}
// 2. Конфигурация окружения
env := os.Getenv("APP_ENV")
if env == "" {
env = "development"
}
switch env {
case "production":
if err := loader.LoadFiles("config/production.yaml"); err != nil {
return err
}
default:
if err := loader.LoadFiles("config/development.env"); err != nil {
return err
}
}
// 3. Локальные переопределения (необязательно)
if _, err := os.Stat("config/local.env"); err == nil {
if err := loader.LoadFiles("config/local.env"); err != nil {
return err
}
}
return nil
}Разделение по функциональности
config/
├── app.json # Конфигурация приложения
├── database.yaml # Конфигурация базы данных
├── redis.env # Конфигурация Redis
└── secrets.json # Конфигурация секретовloader.LoadFiles(
"config/app.json",
"config/database.yaml",
"config/redis.env",
"config/secrets.json",
)Приоритет конфигурации
Аргументы командной строки > Переменные окружения > local конфигурация > конфигурация окружения > base конфигурацияСериализация
Marshal
Сериализация конфигурации в указанный формат:
data := map[string]string{
"HOST": "localhost",
"PORT": "8080",
}envStr, _ := env.Marshal(data)
// HOST=localhost
// PORT=8080jsonStr, _ := env.Marshal(data, env.FormatJSON)
// {
// "HOST": "localhost",
// "PORT": 8080
// }yamlStr, _ := env.Marshal(data, env.FormatYAML)
// HOST: localhost
// PORT: 8080Marshal структуры
type Config struct {
Host string `env:"HOST"`
Port int `env:"PORT"`
}
cfg := Config{Host: "localhost", Port: 8080}envStr, _ := env.Marshal(cfg, env.FormatEnv)jsonStr, _ := env.Marshal(cfg, env.FormatJSON)yamlStr, _ := env.Marshal(cfg, env.FormatYAML)UnmarshalMap
Десериализация в map:
envData := "HOST=localhost\nPORT=8080"
data, _ := env.UnmarshalMap(envData, env.FormatEnv)jsonData := `{"HOST":"localhost","PORT":"8080"}`
data, _ := env.UnmarshalMap(jsonData, env.FormatJSON)yamlData := "HOST: localhost\nPORT: \"8080\""
data, _ := env.UnmarshalMap(yamlData, env.FormatYAML)Автоопределение формата
Передайте env.FormatAuto, чтобы библиотека определила формат по содержимому: data, _ := env.UnmarshalMap(jsonData, env.FormatAuto).
UnmarshalStruct
Десериализация в структуру:
type Config struct {
Host string `env:"HOST"`
Port int `env:"PORT"`
}
var cfg Configenv.UnmarshalStruct("HOST=localhost\nPORT=8080", &cfg, env.FormatEnv)env.UnmarshalStruct(`{"HOST":"localhost","PORT":"8080"}`, &cfg, env.FormatJSON)env.UnmarshalStruct("HOST: localhost\nPORT: \"8080\"", &cfg, env.FormatYAML)Пользовательский формат
Регистрация парсера
// Определение константы формата
const FormatTOML env.FileFormat = 100
// Реализация интерфейса EnvParser
type TOMLParser struct {
cfg env.Config
validator env.Validator
auditor env.FullAuditLogger
}
func (p *TOMLParser) Parse(r io.Reader, filename string) (map[string]string, error) {
// Реализация парсинга TOML
result := make(map[string]string)
// ...
return result, nil
}
// Регистрация парсера
func init() {
env.RegisterParser(FormatTOML, func(cfg env.Config, f *env.ComponentFactory) (env.EnvParser, error) {
return &TOMLParser{
cfg: cfg,
validator: f.Validator(),
auditor: f.Auditor(),
}, nil
})
}Подробнее в Пользовательский парсер.
Полный пример
package main
import (
"fmt"
"log"
"github.com/cybergodev/env"
)
func main() {
// Создание загрузчика
cfg := env.DefaultConfig()
cfg.ExpandVariables = true
loader, err := env.New(cfg)
if err != nil {
log.Fatal(err)
}
defer loader.Close()
// Загрузка смешанной конфигурации
err = loader.LoadFiles(
"config/base.json", // JSON базовая конфигурация
"config/database.yaml", // YAML конфигурация БД
"config/app.env", // .env конфигурация приложения
)
if err != nil {
log.Fatal(err)
}
// Чтение конфигурации
fmt.Printf("App: %s\n", loader.GetString("APP_NAME"))
fmt.Printf("DB Host: %s\n", loader.GetString("DATABASE_HOST"))
fmt.Printf("DB Port: %d\n", loader.GetInt("DATABASE_PORT"))
// Экспорт текущей конфигурации
all := loader.All()
exported, _ := env.Marshal(all, env.FormatEnv)
fmt.Println("\nExported config:")
fmt.Println(exported)
}Связанная документация
- Сериализация - Подробно о сериализации/десериализации
- ComponentFactory API - Определение формата и регистрация парсеров
- Пользовательский парсер - Добавление пользовательских форматов
- Config API - Конфигурация парсинга JSON/YAML