Go言語の設定管理ライブラリViper:基本的な使い方と応用例

1. Viperとは何か

ViperはGoの構成管理ライブラリで、JSON、YAML、TOMLなど様々な形式の設定ファイルに対応し、環境変数やコマンドライン引数からも値を読み取ることができます。

インストール方法:

go get github.com/spf13/viper

2. 基本的な利用方法

2.1 コード内で値を設定・取得する

  • 後の設定が前の設定を上書きするが、設定方法により優先順位が異なる。
  • Get関数でキーが見つからない場合はゼロ値を返す。キーの存在確認にはIsSet()を使う。
func BasicConfigExample() {
    viper.SetDefault("host", "192.168.1.100")
    viper.Set("api_port", 8080)
    
    hostVal := viper.GetString("host")
    portVal := viper.GetInt("api_port")
    
    fmt.Println("ホスト:", hostVal)
    fmt.Println("ポート:", portVal)
    
    // SetDefaultは既存の値を上書きしない
    viper.SetDefault("host", "10.0.0.1")
    fmt.Println("ホスト(変更後):", viper.GetString("host"))
    
    // Setで設定した値はSetDefaultでは上書きされない
    viper.SetDefault("api_port", 9000)
    fmt.Println("ポート(変更試行):", viper.GetInt("api_port"))
}

2.2 設定の優先順位

同じキーに対して異なるAPIで設定した場合の優先順位は以下の通り(高い順):

  • Set()メソッドの明示的な呼び出し(最も優先度が高い)
  • コマンドラインフラグ(実行時に引数が指定された場合のみ)
  • 環境変数
  • 設定ファイル
  • デフォルト値(最も低い優先度)
func PriorityDemo() {
    viper.SetDefault("host", "192.168.1.100")
    
    var ipAddr string
    pflag.StringVar(&ipAddr, "ip", "", "アプリケーションのIPアドレス")
    pflag.Parse()
    viper.BindPFlags(pflag.CommandLine)
    
    fmt.Println("最終的なIP:", viper.GetString("ip"))
}

// 実行例:
// go run main.go → "192.168.1.100"(デフォルト値)
// go run main.go --ip="127.0.0.1" → "127.0.0.1"(フラグが優先)

2.3 設定をファイルに書き出す

JSON、YAML、TOML形式でファイル出力が可能。

type AppConfig struct {
    Location string
    ID       int
}

func SaveConfigToFile() {
    viper.Set("app", AppConfig{Location: "東京", ID: 5})
    viper.Set("username", "admin")
    
    viper.SetConfigType("json")
    if err := viper.SafeWriteConfigAs("settings.json"); err != nil {
        fmt.Println("JSON書き込み失敗:", err)
    } else {
        fmt.Println("JSON書き込み成功")
    }
    
    viper.SetConfigType("yaml")
    if err := viper.SafeWriteConfigAs("settings.yaml"); err != nil {
        fmt.Println("YAML書き込み失敗:", err)
    } else {
        fmt.Println("YAML書き込み成功")
    }
}

生成されるJSON:

{
  "app": {
    "Location": "東京",
    "ID": 5
  },
  "username": "admin"
}

生成されるYAML:

app:
  location: 東京
  id: 5
username: admin

2.4 設定ファイルを読み込む

手順:設定タイプを指定してから、ファイルを読み込む。

func LoadConfigFromFile() {
    viper.SetConfigType("json")
    viper.SetConfigFile("settings.json")
    
    if err := viper.ReadInConfig(); err != nil {
        fmt.Println("設定ファイル読み込み失敗:", err)
        return
    }
    
    appData := viper.Get("app")
    userName := viper.Get("username")
    
    fmt.Println("読み込んだ設定:", appData)
    fmt.Println("ユーザー名:", userName)
}

2.5 設定ファイルの変更を監視する

func WatchConfigChanges() {
    oldViper := viper.New()
    oldViper.SetConfigType("json")
    oldViper.SetConfigFile("settings.json")
    oldViper.ReadInConfig()
    
    var config AppConfig
    if err := viper.Unmarshal(&config); err != nil {
        panic("設定の解析失敗: " + err.Error())
    }
    
    viper.SetConfigType("json")
    viper.SetConfigFile("settings.json")
    viper.WatchConfig()
    viper.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("設定ファイル変更検出:", e.Name, e.Op)
        fmt.Println("変更前の値:", oldViper.Get("app"))
        fmt.Println("変更後の値:", viper.Get("app"))
    })
    
    fmt.Println("監視中...")
    select {}
}

2.6 環境変数を読み取る

func ReadEnvironmentVariables() {
    viper.AutomaticEnv()
    viper.SetEnvPrefix("")
    
    portVar := viper.Get("HTTP_PORT")
    userVar := viper.Get("USER")
    
    fmt.Println("環境変数:", portVar, userVar)
    
    viper.SetEnvPrefix("MYAPP")
    fmt.Println("プレフィックス付き:", viper.Get("version"))
}

2.7 コマンドライン引数を処理する

func HandleCommandLineArgs() {
    var ipAddress string
    var servicePort int
    
    // pflagを使用: go run main.go --ip 10.0.0.1 --port 3000
    // go run main.go -h で全パラメータ表示
    pflag.StringVar(&ipAddress, "ip", "", "サーバーIP")
    pflag.IntVar(&servicePort, "port", 0, "サーバーポート")
    
    pflag.Parse()
    viper.BindPFlags(pflag.CommandLine)
    
    fmt.Println("IP:", viper.Get("ip"))
    fmt.Println("ポート:", viper.Get("port"))
}

タグ: Go Viper 設定管理 JSON YAML

6月25日 21:33 投稿