Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unmarshal using ENV without binding #688

Closed
forward32 opened this issue Apr 17, 2019 · 3 comments · Fixed by #1429
Closed

Unmarshal using ENV without binding #688

forward32 opened this issue Apr 17, 2019 · 3 comments · Fixed by #1429

Comments

@forward32
Copy link

forward32 commented Apr 17, 2019

Hi all,

Having this code:

type RpcConfig struct {
	ServerAddr string `mapstructure:"ADDR"`
}

func main() {
	v := viper.New()
	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	v.AutomaticEnv()

	//v.BindEnv("ADDR")

	c := &RpcConfig{}
	if err := v.Unmarshal(c); err != nil {
		panic(err)
	}

	log.Printf("conf=%+v", c)
}

and running in this way:

ADDR="test" go run main.go

I got config with empty ServerAddr. If I remove comment from binding line it works but why viper couldn't get it from mapstructure tag itself?

Please let me know if I doing something wrong.

@cachance7
Copy link

I was able to work around this limitation by first marshaling my structs to a format viper could read and then using that data as a config. Note the yaml tags in the struct definitions below.

package app

import (
	"bytes"
	"github.com/spf13/viper"
	yaml "gopkg.in/yaml.v2"
)

type APIConfig struct {
	RootURL string `yaml:"rootUrl" mapstructure:"rootUrl"`
}

type HostPortConfig struct {
	Host string `yaml:"host" mapstructure:"host"`
	Port int    `yaml:"port" mapstructure:"port"`
}

type AppConfig struct {
	MyApi     *APIConfig      `yaml:"myapi" mapstructure:"myapi"`
	SrvAddr   *HostPortConfig `yaml:"srvaddr" mapstructure:"srvaddr"`
}

var Config *AppConfig

func init() {
	Config = new(AppConfig)
	Config.New()  // Initializes with some default values (definition not shown)

	// Marshal the struct into a format viper can read
	bs, err := yaml.Marshal(Config)
	if err != nil {
		panic("unable to marshal config to YAML")
	}

        // No bindings here!
	viper.AutomaticEnv()

        // Hydrate viper with fields
	viper.SetConfigType("yaml")
	viper.ReadConfig(bytes.NewBuffer(bs))

        // Now this call will take into account the env as well
	viper.Unmarshal(Config)
}

@forward32
Copy link
Author

forward32 commented May 31, 2019

I guess viper was created to be independent from format, in your case it is .yaml. So you can't use .toml for example without changing of code.

But thanks for comment anyway.

@sagikazarmark
Copy link
Collaborator

Please see and follow the issue above. ☝️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants