Read a YAML file into typed Go data: nested structs, a map, an optional section, durations and defaults. oneyaml.Unmarshal works like encoding/json’s, with yaml struct tags.
The file:
# service.yaml name: web image: nginx:1.27 timeout: 30s env: LOG_LEVEL: info PORT: "8080" healthcheck: path: /healthz interval: 10s
The program:
package main import ( "fmt" "log" "os" "time" oneyaml "oneyaml.dev/go" ) type Service struct { Name string `yaml:"name"` Image string `yaml:"image"` Replicas int `yaml:"replicas,omitempty"` Timeout time.Duration `yaml:"timeout"` Env map[string]string `yaml:"env"` Healthcheck *Healthcheck `yaml:"healthcheck"` } type Healthcheck struct { Path string `yaml:"path"` Interval time.Duration `yaml:"interval"` } func main() { src, err := os.ReadFile("service.yaml") if err != nil { log.Fatal(err) } svc := Service{Replicas: 1} // defaults: a missing key keeps the field as it is if err := oneyaml.Unmarshal(src, &svc, oneyaml.KnownFields()); err != nil { log.Fatal(err) } fmt.Printf("%s runs %s x%d, timeout %v\n", svc.Name, svc.Image, svc.Replicas, svc.Timeout) fmt.Println("env:", svc.Env) if h := svc.Healthcheck; h != nil { fmt.Printf("health check: %s every %v\n", h.Path, h.Interval) } // KnownFields: a key the struct doesn't have is an error, not ignored. err = oneyaml.Unmarshal([]byte("name: web\nimgae: nginx\n"), &svc, oneyaml.KnownFields()) fmt.Println(err) }
web runs nginx:1.27 x1, timeout 30s env: map[LOG_LEVEL:info PORT:8080] health check: /healthz every 10s oneyaml: line 2, column 1: /imgae: field "imgae" not found in type main.Service
Good to know
- Defaults: set them on the value before
Unmarshal. A key that isn’t in the file leaves its field as it was, soReplicasstays 1. Anullvalue also leaves a struct field, number or string as it was. KnownFields()makes a key the struct doesn’t have an error that names it, with its position. Without it, unknown keys are ignored.time.Durationreads itsStringform (30s,1m30s),time.Timea timestamp, and*big.Intany integer.PORT: "8080"is quoted, so it is a string. Plain8080is an integer; reading it into astringfield is a*TypeError, not a silent conversion.- Types with an
UnmarshalYAMLmethod,encoding.TextUnmarshalerorjson.Unmarshalerread themselves, so types written forencoding/json(Kubernetes quantities, say) need no YAML code.
When the shape isn’t known ahead of time, read nodes from a Document: read YAML without a struct.