Reputation: 63
I don't really understand how viper works. This is my code:
configuration.go
var Config *Configuration
type ServerConfiguration struct {
Port string
}
type Configuration struct {
Server ServerConfiguration
}
func Init() {
var configuration *Configuration
viper.SetConfigFile(".env")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("Error reading config file, %s", err)
}
err := viper.Unmarshal(&configuration)
if err != nil {
log.Fatalf("Unable to decode into struct, %v", err)
}
Config = configuration
}
func GetConfig() *Configuration {
return Config
}
.env
SERVER_PORT=:4747
The problem is that Unmarshal does not work When I use for example configuration.Server.Port it's empty
Upvotes: 6
Views: 7938
Reputation: 85683
spf13/viper predominantly uses mapstructure package to convert between one native Go type to another i.e. when un-marshaling. The package internally uses map[string]interface{}
type to store your config (see viper.go - L1327). After that depending on the config type (your case being env
), viper calls the right parsing package to store your config values. For envfile type, it uses subosito/gotenv to put in the above said map type (see viper.go - L1501)
The crux of your problem is how to make viper unmarshal this config in a map to a struct of your choice. This is where the mapstructure package comes in, to unmarshal the map into a nested structure of you have defined. At this point you are left with two options
map[string]interface{}
type, and later put in the appropriate structure using mapstructureFor the sake of simplicity reasons you can do one, which according to a trivial example I've reproduced with your example can be done below
package main
import (
"fmt"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
)
type ServerConfiguration struct {
Port string `mapstructure:"server_port"`
}
type Configuration struct {
Server ServerConfiguration `mapstructure:",squash"`
}
func main() {
var result map[string]interface{}
var config Configuration
viper.SetConfigFile(".env")
if err := viper.ReadInConfig(); err != nil {
fmt.Printf("Error reading config file, %s", err)
}
err := viper.Unmarshal(&result)
if err != nil {
fmt.Printf("Unable to decode into map, %v", err)
}
decErr := mapstructure.Decode(result, &config)
if decErr != nil {
fmt.Println("error decoding")
}
fmt.Printf("config:%+v\n", config)
}
You can make this working example customized depending on your actual use case. More information about the mapstructure squash
tags for embedded structure can be found here
Upvotes: 5