Search code examples
goyamltagsmarshalling

YAML custom tags in Go


I have these nested structs in Go with custom tags for their properties,

type DummyParams struct {
  Param1 string `yaml:"param1"`
  Param2 string `yaml:"param2"`
}

type Dummy struct {
  Name string `yaml:"name"`
  Type string `yaml:"type"`
  Params DummyParams `yaml:"params"`
}

I create some instances of Dummy and add them to a slice,

dummies := make([]Dummy, 0)
dummy1 := Dummy {
    Name: "a"
    Type: "type a"
    Params: DummyParams {
        Param1: "foo"
        Param2: "bar"
    }
}
dummies = append(dummies, dummy1)
dummy2 := Dummy {
    Name: "b"
    Type: "type b"
    Params: DummyParams {
        Param1: "foo"
        Param2: "bar"
    }
}
dummies = append(dummies, dummy2)

Finally I marshal the data and write it to file

yamlData, err := yaml.Marshal(&dummies)
// handle error ...
writeErr := os.WriteFile("foo.yaml", yamlData, 0644)
// handle write error ...

But the yaml I am getting does not have the lower case tagged names, instead it has the upper case Struct names. Anybody know why this is happening and how to fix it?


Solution

  • Blame it on the yaml implementation you're using. If you use gopkg.in/yaml.v3 for example, it works. Try it on the Go Playground. So one solution is to use another YAML implementation, such as gopkg.in/yaml.v3.

    You mentioned in the comments that you're using https://pkg.go.dev/sigs.k8s.io/[email protected]. Its package doc says:

    In short, this library first converts YAML to JSON using go-yaml and then uses json.Marshal and json.Unmarshal to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods MarshalJSON and UnmarshalJSON unlike go-yaml.

    So sigs.k8s.io/[email protected] first marshals to JSON. If you want lowercased field names, use json tags instead of yaml tags:

    import "sigs.k8s.io/yaml"
    
    type DummyParams struct {
        Param1 string `json:"param1"`
        Param2 string `json:"param2"`
    }
    
    type Dummy struct {
        Name   string      `json:"name"`
        Type   string      `json:"type"`
        Params DummyParams `json:"params"`
    }
    

    With this change output contains lowercased names (try it on the Go Playground):

    - name: a
      params:
        param1: foo
        param2: bar
      type: type a
    - name: b
      params:
        param1: foo
        param2: bar
      type: type b
    

    Note that having to use json tags instead of yaml to make it work is just a quirk of the sigs.k8s.io/[email protected] package. If you want to make it work with this package and other yaml implementations, you may provide both json and yaml tags:

    type DummyParams struct {
        Param1 string `json:"param1" yaml:"param1"`
        Param2 string `json:"param2" yaml:"param2"`
    }
    
    type Dummy struct {
        Name   string      `json:"name" yaml:"name"`
        Type   string      `json:"type" yaml:"type"`
        Params DummyParams `json:"params" yaml:"params"`
    }