🏃🏻 들어가며
이번글에서는 지난번 글의 연장선으로 viper 에서 mapstructure 를 활용해 환경 변수 값을 활용하는 방법을 정리하였습니다.
https://helicopter55.tistory.com/94
✅ Viper 설치 및 mapstructure 를 사용해 Env 구조체 할당하기
1) viper 설치하기
go get 명령어를 통해 viper 라이브러리를 다운로드 받습니다.
go get github.com/spf13/viper
go get github.com/spf13/viper
2) Env struct 생성하기
LoadEnvConfiguration() 이후에 env.AppEnv, env.DBHost, env.DBPort 와 방식으로 사용하기 위해 Env struct 를 mapstructure 을 사용해 작성 합니다. .env 파일에 작성된 DB_PORT 환경 변수값은 Env 구조체의 DBPort 에 맵핑 됩니다.
mapstructure | map[string]interface{}로 표현된 설정 값을 사용자가 정의한 구조체로 손쉽게 매핑할 수 있도록 해줍니다.
type Env struct {
AppEnv string `mapstructure:"APP_ENV"`
ServerAddress string `mapstructure:"SERVER_ADDRESS"`
ContextTimeout int `mapstructure:"CONTEXT_TIMEOUT"`
DBHost string `mapstructure:"DB_HOST"`
DBPort string `mapstructure:"DB_PORT"`
DBUser string `mapstructure:"DB_USER"`
DBPass string `mapstructure:"DB_PASS"`
DBName string `mapstructure:"DB_NAME"`
AccessTokenExpiryHour int `mapstructure:"ACCESS_TOKEN_EXPIRY_HOUR"`
RefreshTokenExpiryHour int `mapstructure:"REFRESH_TOKEN_EXPIRY_HOUR"`
AccessTokenSecret string `mapstructure:"ACCESS_TOKEN_SECRET"`
RefreshTokenSecret string `mapstructure:"REFRESH_TOKEN_SECRET"`
}
3) LoadEnvConfiguration 제작하기
viper 를 통해 .env 파일에서 환경 변수 값을 가져오고 mapstructure 을 사용해 Env 구조체에 맵핑 하기 위해 LoadEnvConfiguration 함수를 제작 합니다.
이렇게 불러온 .env 파일의 환경 변수 값은 main 에서 env.DBName 과 같은 방식으로 호출 하여 사용 할 수 있습니다.
package main
import (
"fmt"
"log"
"github.com/spf13/viper"
)
func main() {
env := LoadEnvConfiguration()
dbName := env.DBName
fmt.Println("dbName", dbName)
secret := env.AccessTokenSecret
fmt.Println("secret", secret)
}
type Env struct {
AppEnv string `mapstructure:"APP_ENV"`
ServerAddress string `mapstructure:"SERVER_ADDRESS"`
ContextTimeout int `mapstructure:"CONTEXT_TIMEOUT"`
DBHost string `mapstructure:"DB_HOST"`
DBPort string `mapstructure:"DB_PORT"`
DBUser string `mapstructure:"DB_USER"`
DBPass string `mapstructure:"DB_PASS"`
DBName string `mapstructure:"DB_NAME"`
AccessTokenExpiryHour int `mapstructure:"ACCESS_TOKEN_EXPIRY_HOUR"`
RefreshTokenExpiryHour int `mapstructure:"REFRESH_TOKEN_EXPIRY_HOUR"`
AccessTokenSecret string `mapstructure:"ACCESS_TOKEN_SECRET"`
RefreshTokenSecret string `mapstructure:"REFRESH_TOKEN_SECRET"`
}
func LoadEnvConfiguration() *Env {
env := Env{}
viper.SetConfigFile("config.env")
err := viper.ReadInConfig()
if err != nil {
log.Fatal("Can't find the file .env : ", err)
}
err = viper.Unmarshal(&env)
if err != nil {
log.Fatal("Environment can't be loaded: ", err)
}
if env.AppEnv == "development" {
log.Println("The App is running in development env")
}
return &env
}
✴️ 아쉬운점
처음에는 Env 구조체의 필드에 ServerConfig, DBConfig 와 같은 구조체를 만들어 사용할려고 했었다.
node.js 에서는 이런 방식으로 많이 사용했었기에 이런 방법을 찾아보고 있었다.
하지만, 아직은 숙련도가 부족한 탓인지 .env 환경 변수값을 가져온 케이스를 작성하지 못했다.
추후에 방법을 알게 되면 링크를 여기에 추가해놓겠습니다 :(
아래는 제가 처음에 의도했던 코드 입니다.
type Env struct {
ServerConfig ServerConfig
DBConfig DBConfig
}
type ServerConfig struct {
AppEnv string `mapstructure:"APP_ENV"`
Address string `mapstructure:"SERVER_ADDRESS"`
}
type DBConfig struct {
Host string `mapstructure:"DB_HOST"`
Port string `mapstructure:"DB_PORT"`
User string `mapstructure:"DB_USER"`
Pass string `mapstructure:"DB_PASS"`
Name string `mapstructure:"DB_NAME"`
}
📍마무리하며
이번 글을 통해서 viper 를 활용해 .env 파일의 환경 변수 값을 가져와 mapstructure 를 사용해 Env 구조체 할당하는데 도움이 되었으면 좋겠습니다 :)
실제 동작하는 코드는 여기서 확인 하실 수 있습니다.
댓글