I have a YAML like one below.
connections:
- name: demo
hosts:
- demo.example.com:9200
username: admin
password: password
ssl: true
ssl_verify: true
version: 7
- name: test
hosts:
- "test.example.com:9200"
username: admin
password: password
As you can see ssl
and ssl_verify
is not set in the second item of the list. I want them by default to be true
, however, it is not happening. I tried different solutions.
viper.SetDefault("connections[].ssl", "true")
type Config struct {
Connections []struct {
Name string
Hosts []string
Username string
Password string
Ssl bool `default:"true"`
SslVerify bool `default:"true"`
Version int
}
}
...
err := defaults.Set(config)
Manually looping through the list of structures. While these method work with strings, it does not work with boolean values because they are already initialized with false
after unmarshalling and we don't know for sure whether false
is entered by the user or not.
Using pointers with boolean values. This works as uninitialized values are equal to nil
and they are easy to catch. However, it will require to dereference pointers when using config struct, which is not very convenient. Alternatively, a new struct can be generated based on the one that comes from unmarshalling.
type Config struct {
Connections []struct {
Name string
Hosts []string
Username string
Password string
Ssl *bool
SslVerify *bool
Version int
}
}
Solutions 4 and 5 will likely work, but I am wondering if there anything better than that.
Any ideas?
You can use a function to do the job:
type Connection struct {
Name string
Hosts []string
Username string
Password string
Ssl *bool
SslVerify bool
Version int
}
// If Ssl is nil, returns true
// otherwise the value
func (c Connection) IsSSL() bool {
return c.Ssl == nil || *c.Ssl
}
type Config struct {
Connections []Connection
}
EDIT
Or, even better, simply invert the logic of your booleans:
type Connection struct {
Name string
Hosts []string
Username string
Password string
SkipSsl bool
SkipSslVerify bool
Version int
}
This way, SSL would be used unless explicitly told different in the config - which would stand out when somebody reads the config.
I figured it out. I am using github.com/creasty/defaults
in the UnmarshalYAML
callback.
type Config struct {
Connections []Connection
}
type Connection struct {
Name string
Hosts []string
Username string
Password string
Ssl bool `default:"true"`
SslVerify bool `default:"true" yaml:"ssl_verify"`
Version int `version:"7"`
}
func (s *Connection) UnmarshalYAML(unmarshal func(interface{}) error) error {
defaults.Set(s)
type plain Connection
if err := unmarshal((*plain)(s)); err != nil {
return err
}
return nil
}
Also this solution pairs well with https://github.com/dealancer/validate for validation purpose.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With