1
votes

I'm calling an API which will return Json objects like this:

{
  name: "XXX"
  type: "TYPE_1"
  shared_fields: {...}
  type_1_fields: {...}
  ..
  type_2_fields: {...}
}

Based on different types, this object will have different kinds of fields, but these fields are certain for different types. So, I unmarshal the Json string to map[string]interface{} to fetch the the different type but how can I turn these map[string]interface{} to a certain struct?

  var f map[string]interface{}
  err := json.Unmarshal(b, &f)
  type := f["type"]
  switch type {
    case "type_1":
      //initialize struct of type_1
    case "type_2":
      //initialize struct of type_2
  }
3

3 Answers

2
votes

For this sort of two-step json decoding you will probably want to check out json.RawMessage. It allows you to defer processing of parts of your json response. The example in the docs shows how.

0
votes

One way to do it would be to have a constructor function (one that starts with New…) that takes a map as input parameter.

A second way, much slower in my opinion, would be to redo the unmarshalling to the right struct type.

0
votes

If the types are different enough and you want to be lazy you can just try to decode it in each format:

  f1 := type1{}
  err := json.Unmarshal(b, &f1)
  if err == nil {
      return f1
  }
  f2 := type2{}
  err := json.Unmarshal(b, &f2)
  if err == nil {
     return f2
  }
  ...

If the objects are similar or you want to be less lazy, you could just decode the type and then do something:

  type BasicInfo struct {
     Type string `json:"type"`
  }

  f := BasicInfo{}
  err := json.Unmarshal(b, &f)
  switch f.Type {
    case "type_1":
      //initialize struct of type_1
    case "type_2":
      //initialize struct of type_2
  }