Skip to main content
Go Language Fundamentals for Beginners to Advanced
CHAPTER 22 Beginner

JSON Handling in Go

Updated: May 17, 2026
5 min read

# CHAPTER 22

JSON Handling in Go

1. Introduction

Modern applications do not exist in isolation. If your Go backend needs to talk to a React frontend, a mobile app, or a Stripe payment gateway, it must speak the universal language of the web: JSON (JavaScript Object Notation). In this chapter, we will learn how to use Go's standard encoding/json package to convert Go Structs into JSON (Marshaling), and convert incoming JSON back into Go Structs (Unmarshaling).

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Convert a Go Struct into a JSON string (Marshal).
  • Convert a JSON string into a Go Struct (Unmarshal).
  • Understand and apply Struct Tags.
  • Handle unknown JSON structures.

3. Struct Tags (The Secret Ingredient)

In Go, exported struct fields MUST be capitalized (e.g., FirstName). However, standard JSON uses lowercase or snakecase (e.g., "firstname").

To bridge this gap, Go uses Struct Tags. These are backtick-quoted strings placed after the struct field. They tell the JSON encoder exactly how to format the keys.

go
12345678910111213
type User struct {
    // Go sees 'ID', but JSON will see 'id'
    ID        int    `json:"id"`
    
    // JSON will see 'first_name'
    FirstName string `json:"first_name"`
    
    // omitempty means: If this is empty, don't include it in the JSON at all
    Email     string `json:"email,omitempty"`
    
    // A dash means: NEVER include this in JSON (Great for passwords!)
    Password  string `json:"-"`
}

4. Encoding (Marshaling) to JSON

To convert a Struct into a slice of JSON bytes, we use json.Marshal().
go
123456789101112131415161718192021222324
package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    u := User{
        ID:        1,
        FirstName: "Alice",
        Password:  "supersecret", // This will be hidden!
    }

    // Marshal returns ([]byte, error)
    jsonData, err := json.Marshal(u)
    if err != nil {
        fmt.Println("Error marshaling JSON:", err)
        return
    }

    // Convert bytes to string for printing
    fmt.Println(string(jsonData))
}

Output: {"id":1,"first_name":"Alice"} *(Notice how the Email was omitted, the Password was hidden, and the keys are lowercase!)*

5. Decoding (Unmarshaling) from JSON

When a frontend sends JSON data to your server, you need to parse it back into a Go Struct. We use json.Unmarshal().

Critical Memory Rule: You must pass a Pointer (&) of your struct to Unmarshal, so it can write the parsed data directly into your variable's memory address!

go
1234567891011121314151617
func main() {
    // Incoming JSON from the internet
    jsonString := `{"id": 42, "first_name": "Bob", "email": "bob@test.com"}`
    
    // Prepare an empty Go struct
    var newUser User

    // Unmarshal requires a slice of bytes, and a POINTER to the struct
    err := json.Unmarshal([]byte(jsonString), &newUser)
    
    if err != nil {
        fmt.Println("Error parsing JSON:", err)
        return
    }

    fmt.Printf("Successfully parsed! User %s has email %s\n", newUser.FirstName, newUser.Email)
}

6. Dealing with Unknown JSON (Unstructured Data)

What if an external API sends you JSON, but you don't know the structure in advance, so you can't build a Struct for it? You can unmarshal the JSON into a flexible map[string]interface{} (A map where the keys are strings, and the values can be literally anything).
go
12345678
func main() {
    rawJson := `{"status": "success", "data": 100}`
    
    var result map[string]interface{}
    json.Unmarshal([]byte(rawJson), &result)
    
    fmt.Println("Status:", result["status"])
}

*(Note: While this works, using strongly-typed Structs is always preferred in Go for performance and safety).*

7. Common Mistakes

  • Unexported Struct Fields: If your struct field is lowercase (name string instead of Name string), the json package (which is an external package) cannot see it. It will silently ignore the field, and your generated JSON will be mysteriously empty. Always capitalize struct fields used for JSON!
  • Forgetting the Pointer in Unmarshal: Calling json.Unmarshal(data, newUser) instead of &newUser. Go will return an error because it cannot modify a copy of the struct.

8. Best Practices

  • Pretty Print: If you are debugging and want human-readable JSON with indents and newlines, use json.MarshalIndent(u, "", " ") instead of standard Marshal.

9. Exercises

  1. 1. Create a Product struct with Name, Price, and InStock fields. Use struct tags to make them lowercase in JSON.
  1. 2. Instantiate a Product, Marshal it to JSON, and print the resulting string.

10. MCQs with Answers & Explanations

Question 1

Which standard library package is used to handle JSON in Go?

Question 2

What is the process of converting a Go Struct into a JSON string called?

Question 3

What is the process of converting a JSON string into a Go Struct called?

Question 4

What is the primary purpose of Struct Tags (e.g., ` json:"id" )?

Question 5

What does the struct tag json:"-" do?

Question 6

What happens if a struct field is named password (lowercase 'p') when Marshaling?

Question 7

What data type does json.Marshal() output?

Q8. When calling json.Unmarshal(data, &user), why MUST you use an ampersand (&)? a) Because Unmarshal requires a pointer to write the parsed data directly into the struct's memory b) It looks cool Answer: a) Because Unmarshal requires a pointer.
Question 9

If you receive totally random, unknown JSON, what data type can you unmarshal it into?

Question 10

What function produces human-readable, formatted JSON with indents?

11. Interview Preparation

Interview Questions:
  1. 1. Why must struct fields be capitalized to be converted to JSON? (Answer: Because the encoding/json package is an external package, and Go's visibility rules state that only capitalized fields are exported/visible outside the package).
  1. 2. How do you exclude a field from being marshaled into JSON? (Answer: Using the json:"-" struct tag).

12. Summary

JSON handling in Go relies on Structs and Struct Tags. By defining rigid data models, Go ensures that APIs are type-safe and predictable.
Marshal encodes our data for the web, and Unmarshal decodes incoming web data into memory.

13. Next Chapter Recommendation

Now that we can speak the language of the web (JSON), it is time to build a web server! In Chapter 23: Building REST APIs in Go, we will use the
net/http` package to open a network port, listen for requests, and return real JSON responses to a browser.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·