다중 형식 구성
env 라이브러리는 .env, JSON, YAML 세 가지 구성 형식을 지원하며, 형식을 자동으로 감지하고 로드할 수 있습니다.
형식 감지
자동 감지 규칙
| 확장자 | 형식 | 상수 |
|---|---|---|
.env | .env 형식 | FormatEnv |
.json | JSON | FormatJSON |
.yaml, .yml | YAML | FormatYAML |
| 기타 | 자동 | FormatAuto |
DetectFormat 함수
go
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"다중 형식 파일 로드
단일 형식
go
loader.LoadFiles("config.env")
loader.LoadFiles("settings.json")
loader.LoadFiles("secrets.yaml")혼합 형식
go
// 각 파일의 형식을 자동 감지
loader.LoadFiles("config.env", "settings.json", "secrets.yaml")덮어쓰기 순서
나중에 로드된 파일이 먼저 로드된 것을 덮어씁니다:
go
// 순서: base -> env -> json -> yaml
loader.LoadFiles(
".env", // 기본 구성
"config.json", // .env 덮어쓰기
"secrets.yaml", // config.json 덮어쓰기
)JSON 형식
파일 구조
json
{
"APP_NAME": "myapp",
"APP_PORT": "8080",
"DEBUG": "true",
"DATABASE": {
"HOST": "localhost",
"PORT": "5432"
}
}팁
중첩 객체는 DATABASE_HOST, DATABASE_PORT로 평탄화됩니다.
키 이름 해석
JSON/YAML의 중첩 구조는 평탄화되어 저장됩니다. 라이브러리는 다양한 키 이름 접근 방식을 지원합니다:
go
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 배열은 인덱스가 포함된 키로 평탄화됩니다:
json
{
"servers": [
{ "host": "server1.example.com", "port": 8080 },
{ "host": "server2.example.com", "port": 8081 }
]
}go
// 플랫 키 이름으로 배열 요소 접근
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 파싱 구성
go
cfg := env.DefaultConfig()
// null 값을 빈 문자열로 변환(기본값 true)
cfg.JSONNullAsEmpty = true
// 숫자를 문자열로 변환(기본값 true)
cfg.JSONNumberAsString = true
// 불리언을 문자열로 변환(기본값 true)
cfg.JSONBoolAsString = true
// 최대 중첩 깊이(기본값 10)
cfg.JSONMaxDepth = 20타입 변환 예제
json
{
"PORT": 8080,
"DEBUG": true,
"TIMEOUT": 30,
"RATES": [0.1, 0.2, 0.3]
}go
// 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 형식
파일 구조
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과 동일한 평탄화 규칙을 사용합니다:
go
loader.LoadFiles("config.yaml")
// 플랫 키 이름으로 접근
host := loader.GetString("DATABASE_HOST") // localhost
user := loader.GetString("DATABASE_USER") // postgres배열 접근
YAML 리스트는 인덱스가 포함된 키로 평탄화됩니다:
yaml
servers:
- host: server1.example.com
port: 8080
- host: server2.example.com
port: 8081go
// 플랫 키 이름으로 접근
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 파싱 구성
go
cfg := env.DefaultConfig()
// null/~ 값을 빈 문자열로 변환(기본값 true)
cfg.YAMLNullAsEmpty = true
// 숫자를 문자열로 변환(기본값 true)
cfg.YAMLNumberAsString = true
// 불리언을 문자열로 변환(기본값 true)
cfg.YAMLBoolAsString = true
// 최대 중첩 깊이(기본값 10)
cfg.YAMLMaxDepth = 15타입 변환 예제
yaml
PORT: 8080
DEBUG: true
TIMEOUT: 30
RATES:
- 0.1
- 0.2
- 0.3go
// 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 형식
파일 구조
bash
# 주석
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변수 확장
go
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} | 변수가 없을 때 기본값 사용 |
bash
# 확장 예제
HOST=localhost
PORT=8080
# 다른 변수 참조
URL=http://${HOST}:${PORT}
# 기본값(다른 변수 참조, 정의되지 않은 경우 기본값 사용)
TIMEOUT_VALUE=${TIMEOUT:-30s}
DEBUG_VALUE=${DEBUG:-false}export 구문
bash
# export 접두사 지원(AllowExportPrefix = true일 때)
export DATABASE_HOST=localhost
export DATABASE_PORT=5432YAML 스타일 구문
go
cfg := env.DefaultConfig()
cfg.AllowYamlSyntax = true // YAML 스타일 활성화bash
# YAML 스타일 키-값 쌍 지원
KEY: value
ANOTHER_KEY: "quoted value"혼합 구성 모드
개발/프로덕션 분리
text
config/
├── base.json # 기본 구성
├── development.env # 개발 덮어쓰기
├── production.yaml # 프로덕션 덮어쓰기
└── local.env # 로컬 덮어쓰기(커밋하지 않음)go
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
}기능별 분리
text
config/
├── app.json # 애플리케이션 구성
├── database.yaml # 데이터베이스 구성
├── redis.env # Redis 구성
└── secrets.json # 키 구성go
loader.LoadFiles(
"config/app.json",
"config/database.yaml",
"config/redis.env",
"config/secrets.json",
)구성 우선순위
text
명령줄 매개변수 > 환경 변수 > local 구성 > 환경 구성 > base 구성직렬화
Marshal
구성을 지정된 형식으로 직렬화합니다. 먼저 데이터를 준비한 후 대상 형식으로 env.Marshal을 호출합니다:
go
data := map[string]string{
"HOST": "localhost",
"PORT": "8080",
}go
envStr, _ := env.Marshal(data)
// HOST=localhost
// PORT=8080go
jsonStr, _ := env.Marshal(data, env.FormatJSON)
// {
// "HOST": "localhost",
// "PORT": 8080
// }go
yamlStr, _ := env.Marshal(data, env.FormatYAML)
// HOST: localhost
// PORT: 8080Marshal 구조체
go
type Config struct {
Host string `env:"HOST"`
Port int `env:"PORT"`
}
cfg := Config{Host: "localhost", Port: 8080}go
envStr, _ := env.Marshal(cfg, env.FormatEnv)go
jsonStr, _ := env.Marshal(cfg, env.FormatJSON)go
yamlStr, _ := env.Marshal(cfg, env.FormatYAML)UnmarshalMap
map으로 역직렬화합니다:
go
envData := "HOST=localhost\nPORT=8080"
data, _ := env.UnmarshalMap(envData, env.FormatEnv)go
jsonData := `{"HOST":"localhost","PORT":"8080"}`
data, _ := env.UnmarshalMap(jsonData, env.FormatJSON)go
yamlData := "HOST: localhost\nPORT: \"8080\""
data, _ := env.UnmarshalMap(yamlData, env.FormatYAML)자동 형식 감지
env.FormatAuto를 전달하면 라이브러리가 콘텐츠로 형식을 자동 판단합니다: data, _ := env.UnmarshalMap(jsonData, env.FormatAuto).
UnmarshalStruct
구조체로 역직렬화합니다:
go
type Config struct {
Host string `env:"HOST"`
Port int `env:"PORT"`
}
var cfg Configgo
env.UnmarshalStruct("HOST=localhost\nPORT=8080", &cfg, env.FormatEnv)go
env.UnmarshalStruct(`{"HOST":"localhost","PORT":"8080"}`, &cfg, env.FormatJSON)go
env.UnmarshalStruct("HOST: localhost\nPORT: \"8080\"", &cfg, env.FormatYAML)커스텀 형식
파서 등록
go
// 형식 상수 정의
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
})
}자세한 내용은 커스텀 파서를 참조하세요.
완전한 예제
go
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 파싱 구성