Working with JSON in Go
Go has excellent built-in support for JSON through the encoding/json package.
This guide covers marshaling, unmarshaling, validation, and best practices for handling JSON in Go.
Unmarshaling JSON (Parsing)
Use json.Unmarshal() to parse JSON into Go structs:
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
IsAdmin bool `json:"is_admin"`
}
func main() {
jsonStr := `{"name": "John", "age": 30, "email": "john@example.com", "is_admin": true}`
var user User
err := json.Unmarshal([]byte(jsonStr), &user)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(user.Name) // John
fmt.Println(user.Age) // 30
fmt.Println(user.IsAdmin) // true
} Marshaling JSON (Serializing)
Use json.Marshal() to convert Go values to JSON:
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Hobbies []string `json:"hobbies"`
Active bool `json:"active"`
}
func main() {
user := User{
Name: "Jane",
Age: 25,
Hobbies: []string{"reading", "coding"},
Active: true,
}
// Basic marshaling
jsonBytes, err := json.Marshal(user)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(string(jsonBytes))
// Pretty print with indentation
prettyBytes, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(prettyBytes))
} JSON Validation
package main
import (
"encoding/json"
"fmt"
)
func isValidJSON(str string) bool {
var js json.RawMessage
return json.Unmarshal([]byte(str), &js) == nil
}
type ValidationResult struct {
Valid bool `json:"valid"`
Error string `json:"error,omitempty"`
Type string `json:"type,omitempty"`
}
func validateJSON(str string) ValidationResult {
var js interface{}
err := json.Unmarshal([]byte(str), &js)
if err != nil {
return ValidationResult{
Valid: false,
Error: err.Error(),
}
}
var jsonType string
switch js.(type) {
case map[string]interface{}:
jsonType = "object"
case []interface{}:
jsonType = "array"
default:
jsonType = "primitive"
}
return ValidationResult{
Valid: true,
Type: jsonType,
}
}
func main() {
fmt.Println(isValidJSON(`{"name": "John"}`)) // true
fmt.Println(isValidJSON("{invalid}")) // false
} Working with Files
package main
import (
"encoding/json"
"os"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
// Write JSON to file
user := User{Name: "John", Age: 30}
file, _ := os.Create("output.json")
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
encoder.Encode(user)
// Read JSON from file
readFile, _ := os.Open("output.json")
defer readFile.Close()
var readUser User
json.NewDecoder(readFile).Decode(&readUser)
} Struct Tags
Go uses struct tags to control JSON field names and behavior:
json:"name"- Rename field in JSONjson:"name,omitempty"- Omit if empty/zero valuejson:"-"- Always omit this fieldjson:"name,string"- String representation for numbers
Best Practices
- Always check errors from
json.Marshal()andjson.Unmarshal() - Use struct tags to control JSON field names
- Use
omitemptyto exclude empty/zero values - Use
json.RawMessagefor deferred parsing - Use streaming (Encoder/Decoder) for HTTP handlers
- Remember that numbers in
interfacebecomefloat64 - Use
json.Valid()for quick JSON validation