goviper-go

How to iterate over yml sections with structs?


I use viper. I'm trying to get info from structs with yml-config.

type Config struct {
    Account       User           `mapstructure:"user"`      
}

type User struct {
    Name       string           `mapstructure:"name"`
    Contacts   []Contact        `mapstructure:"contact"`
}

type Contact struct {
    Type          string          `mapstructure:"type"`
    Value         string          `mapstructure:"value"`
}

func Init() *Config {
    conf := new(Config)

    viper.SetConfigType("yaml")
    viper.ReadInConfig()
    ...
    viper.Unmarshal(conf)
    return conf
}

...
config := Init()
...
for _, contact := range config.Account.Contacts {
   type := contact.type
   vlaue := contact.value
}

And config.yml

user:
  name: John
  contacts:
    email:
      type: email
      value: test@test.com
    skype:
      type: skype
      value: skypeacc

Can I get structure items like this? I could not get contact data like that. Is it possible?


Solution

  • I think the only significant problem is that in your data structures you've declared Contacts as a list, but in your YAML file it's a dictionary. If you structure your input file like this:

    user:
      name: John
      contacts:
        - type: email
          value: test@test.com
        - type: skype
          value: skypeacc
    

    Then you can read it like this:

    package main
    
    import (
        "fmt"
    
        "github.com/spf13/viper"
    )
    
    type Config struct {
        User User
    }
    
    type User struct {
        Name     string
        Contacts []Contact
    }
    
    type Contact struct {
        Type  string
        Value string
    }
    
    func main() {
        var cfg Config
    
        viper.SetConfigName("config")
        viper.AddConfigPath(".")
        err := viper.ReadInConfig()
        if err != nil {
            panic(err)
        }
        viper.Unmarshal(&cfg)
        fmt.Println("user: ", cfg.User.Name)
        for _, contact := range cfg.User.Contacts {
            fmt.Println("  ", contact.Type, ": ", contact.Value)
        }
    }
    

    The above code is runnable as-is; you should just be able to drop it into a file and build it. When I run the above example, I get as output:

    user:  John
       email :  test@test.com
       skype :  skypeacc