jsondictionarygointerfacetype-assertion

Better way to type assert interface to map in Go


I am storing JSON in a file in which it has nested objects.

The structure looks like this:

{
  "users" : {
    "enxtropayy": {
      "pass": "",
      "root": true,
      "admin": true,
      "moderator": true
    }
  }
}

Soooo, I want to be able to access the "enxtropayy" user via Go:

usr, _ := ioutil.ReadFile("userInfo.JSON")
var data map[string]interface{}
json.Unmarshal(usr,&data)
fmt.Println(data["users"])

It prints map[enxtropayy:map[admin:true moderator:true pass: root:true]]

This is great and all, but I can't go deeper than one layer, and I found out that it's because interfaces don't have keys.

So instead I re-wrote my Go code to look like this:

var data interface{}
json.Unmarshal(usr,&data)
fmt.Println(data.(interface{}).(map[string]interface{})["users"].(interface{}).(map[string]interface{})["enxtropayy"])

It works! But, I have to do .(map[string]interface{})["keyName"] every time I want to access another nested layer and that doesn't seem very "neat" and is a bit tedious to write. It also seems unnecessary and is probably not the best practice. The whole "type assertion" and "interfaces/maps" is new to me so I don't know much about what I'm doing, which is something I want to improve on.

Is there another way I can type assert an interface to a map (or a better way to store the JSON in Go altogether), and could you also explain how it works (give a man a fish and he will eat for a day; teach a man to fish and he will eat for a living)?


Solution

  • It's better to just use struct when possible:

    package main
    
    import (
       "encoding/json"
       "fmt"
    )
    
    const s = `
    {
       "users" : {
          "enxtropayy": {
             "admin": true, "moderator": true, "root": true,
             "pass": ""
          }
       }
    }
    `
    
    func main() {
       var t struct {
          Users map[string]struct {
             Admin, Moderator, Root bool
             Pass string
          }
       }
       json.Unmarshal([]byte(s), &t)
       // {Users:map[enxtropayy:{Admin:true Moderator:true Root:true Pass:}]}
       fmt.Printf("%+v\n", t)
    }