Unmarshal JSON Field with Variable Type

· 137 words · 1 minute read

The API endpoint I’m querying returns a JSON object, where some fields are either an empty string or a map[string]interface{}. The map[string]interface{} actually follows a consistent schema, but since the actual received value is not a consistent type, I’m having to put the type as interface{} and check those fields specially.

package main

import (
	"encoding/json"
	"log"
)

type Foo struct {
	Name       string      `json:"name"`
	SillyField interface{} `json:"silly_field"`
}

func printSillyField(f Foo) {
	if f.SillyField == nil {
		log.Println("is nil")
		return
	}

	if v, ok := f.SillyField.(map[string]interface{}); ok {
		log.Printf("is interface. key: %s, val: %s\n", v["key"].(string), v["val"].(string))
	} else {
		log.Printf("is string: %s", f.SillyField)
	}
}

func main() {
	resNope := json.RawMessage(`{"name":"myfoo"}`)
	resIsString := json.RawMessage(`{"name":"myfoo","silly_field":""}`)
	resIsNestedJson := json.RawMessage(`{"name":"myfoo","silly_field":{"key":"foo","val":"bar"}}`)

	var fooNo Foo
	json.Unmarshal(resNope, &fooNo)
	printSillyField(fooNo)

	var fooString Foo
	json.Unmarshal(resIsString, &fooString)
	printSillyField(fooString)

	var fooNested Foo
	json.Unmarshal(resIsNestedJson, &fooNested)
	printSillyField(fooNested)
}