6. map string interface{}

map[string]interface{}

Sometimes you have to deal with JSON data of unknown or varying structure in Go. In those instances map[string]interface{} offers a flexible way to handle it without predefined structs.

Think about it: a JSON object is a key-value pair, where the key is a string and the value can be any JSON type. map[string]interface{} is a map where the key is a string and the value can be any Go type.

var data map[string]interface{}
jsonString := `{"name": "Alice", "age": 30, "address": {"city": "Wonderland"}}`
json.Unmarshal([]byte(jsonString), &data)
fmt.Println(data["name"])  // Output: Alice
fmt.Println(data["address"].(map[string]interface{})["city"])  // Output: Wonderland

any is an aliasarrow-up-right for interface{}

Go JSON - map[string]interface{} Notes

The Problem

Sometimes you don't know the JSON structure ahead of time, or it varies. You can't create a struct for it.

Example varying JSON:

// Sometimes:
{"type": "user", "name": "Alice"}

// Other times:
{"type": "org", "company": "Acme", "employees": 50}

Different fields! Can't use one struct.

The Solution: map[string]interface{}

What this means:

  • map[string]___ = keys are strings (JSON keys are always strings)

  • interface{} = values can be any type

Breaking Down the Type

Why This Works for JSON

JSON structure:

Go map equivalent:

Example Usage

Accessing Nested Values

1

Step by step

  1. data["address"] - get the address value (type interface{})

  2. .(map[string]interface{}) - type assertion (tell Go it's a map)

  3. ["city"] - access the "city" key in that map

Type Assertions Explained

When you pull a value out of interface{}, you need to tell Go what type it is:

Common type assertions:

any is the Same as interface{}

any is just an alias (shorter name) for interface{}.

Complete Example

Safe Type Assertion (Check for Errors)

When to Use map[string]interface{}

Good for:

  • Unknown JSON structure

  • Varying JSON structure

  • Quick prototyping

  • Config files with flexible structure

Bad for:

  • Known, fixed structure (use structs instead)

  • Type safety (you lose it with interface{})

  • Performance (type assertions have overhead)

Structs vs map[string]interface{}

With Struct (better when structure is known)

With map[string]interface{} (when structure unknown)

JSON Number Gotcha

Important: JSON numbers always decode to float64, even if they're integers!

Common Patterns

Check if Key Exists

Iterate Over Keys

Nested Access with Safety

Key Takeaways

  1. map[string]interface{} handles JSON with unknown structure

  2. Keys are strings, values can be any type

  3. Type assertions required to use values: .(type)

  4. any = interface{} (same thing)

  5. JSON numbers become float64

  6. Use structs when structure is known (better type safety)

Quick Reference

JSON Type
Go Type in interface{}

String

string

Number

float64

Boolean

bool

Object

map[string]interface{}

Array

[]interface{}

null

nil

Assignment

A junior developer's deadline is looming. They've been tasked with creating functions to retrieve and log various resources from Jello's API. Rather than making multiple structs and type-safe functions, the junior developer has decided to make two flexible functions. Help them complete their task before their boss, Wayne Lagner, asks them to refactor it.

Complete the getResources and logResources functions.

  • getResources takes a url string and returns a slice of maps []map[string]interface{} and an error. It's a slice of maps because the API response is an array of JSON objects.

  • logResources takes a slice of maps []map[string]interface{} and prints its keys and values to the console. Because maps are unsorted we will be adding formatted strings to a slice of strings []string which is then sorted.

1

getResources()

  • Decode the response body into a slice of maps []map[string]interface{} and return it.

2

logResources()

  • Iterate over the slice of map[string]interface{}

  • For each map[string]interface{} get its keys and values using range and append it to formattedStrings as Key: %s - Value: %v, where %s is the key and %v is the value.

You do not need to account for nested JSON objects. Assume they are neat key-value pairs, one level deep.

Example output from one issue:

Starter Code

chevron-rightSolutionhashtag