Search code examples
goyamlviper-go

viper yaml config sequence


I'm trying to read a yaml config file using viper (see viper docs). But I cannot see a way to read the sequence of map values under issue-types. I've tried the various Get_ methods but none seem to support this.

remote:
  host: http://localhost/
  user: admin
  password:  changeit

mapping:
    source-project-key: IT
    remote-project-key: SCRUM

issue-types:
  - source-type: Incident
    remote-type: Task
  - source-type: Service Request
    remote-type: Task
  - source-type: Change
    remote-type: Story
  - source-type: Problem
    remote-type: Task

I'd like to be able to iterate over the sequence of map[strings]


Solution

  • If you look closely at the different Get methods available, you'll see that the return types are string, []string, map[string]interface{}, map[string]string and map[string][]string.

    However, the type of the value associated with "issue-types" is []map[string]string. So, the only way to get this data is through the Get method and using type assertions.

    Now, the following code produces the appropriate type of issue_types, which is []map[string]string.

    issues_types := make([]map[string]string, 0)
    var m map[string]string
    
    issues_i := viper.Get("issue-types")
    // issues_i is interface{}
    
    issues_s := issues_i.([]interface{})
    // issues_s is []interface{}
    
    for _, issue := range issues_s {
        // issue is an interface{}
    
        issue_map := issue.(map[interface{}]interface{})
        // issue_map is a map[interface{}]interface{}
    
        m = make(map[string]string)
        for k, v := range issue_map {
            m[k.(string)] = v.(string)
        }
        issues_types = append(issues_types, m)
    }
    
    fmt.Println(reflect.TypeOf(issues_types))
    # []map[string]string
    
    fmt.Println(issues_types)
    # [map[source-type:Incident remote-type:Task]
    #  map[source-type:Service Request remote-type:Task]
    #  map[source-type:Change remote-type:Story]
    #  map[source-type:Problem remote-type:Task]]
    

    Note that I did not do any safety check in order to make the code smaller. However, the correct way of doing type assertion is:

    var i interface{} = "42"
    str, ok := i.(string)
    if !ok {
        // A problem occurred, do something
    }