Infrastructure is YAML and JSON all the way down. K8s manifests, Terraform configs, CI pipelines, Helm values.
import "encoding/json"
type Pod struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Image string `json:"image,omitempty"` // omit if empty
Replicas int `json:"replicas"`
}
// Unmarshal: JSON bytes → struct
data := []byte(`{"name":"web","namespace":"prod","replicas":3}`)
var pod Pod
if err := json.Unmarshal(data, &pod); err != nil {
return fmt.Errorf("parsing JSON: %w", err)
}
// Marshal: struct → JSON bytes
out, err := json.MarshalIndent(pod, "", " ")
if err != nil {
return fmt.Errorf("encoding JSON: %w", err)
}
fmt.Println(string(out))
Tags control how fields map to JSON/YAML keys:
type Config struct {
APIVersion string `json:"apiVersion" yaml:"apiVersion"`
Kind string `json:"kind" yaml:"kind"`
Metadata Metadata `json:"metadata" yaml:"metadata"`
Spec map[string]any `json:"spec" yaml:"spec"`
}
import "gopkg.in/yaml.v3"
// Same patterns as JSON
data, err := os.ReadFile("deployment.yaml")
if err != nil { ... }
var config Config
if err := yaml.Unmarshal(data, &config); err != nil {
return fmt.Errorf("parsing YAML: %w", err)
}
K8s manifests have many fields you might not care about:
// Option 1: use map[string]any for flexible parsing
var raw map[string]any
yaml.Unmarshal(data, &raw)
// Option 2: define only the fields you need — unknown fields are silently ignored
type Minimal struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
}
// Option 3: strict mode — reject unknown fields (json only)
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()