Problem

If you have a file.yaml and you don’t know the structure of the contents in file.yaml, how do you convert the contents to json?

Let’s say the file.yaml looks like this:

1
2
3
4
5
6
flags:
  myBoolFlag:
    state: ENABLED
    variants:
      'on': true
      'off': false

Solution

If you don’t know the structure of the yaml contents, you can use map[string]interface{} like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
    "fmt"
    "gopkg.in/yaml.v3"
    "encoding/json"
    "os"
)

func main() {

    rawFile, err := os.ReadFile("file.yaml")
    if err != nil {
        panic(err)
    }
	
	var ms map[string]interface{} // intermediate representation that json.Marshal can understand
    // Unmarshal to intermediate representation that can be fed to json.Marshal
	if err := yaml.Unmarshal(rawFile, &ms); err != nil {
		panic(err)
	}

    // Use intermediate representation from above as input
    // `MarshalIndent` instead of `Marshal` to show prettier output
	r, err := json.MarshalIndent(ms, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Println("converted json:", string(r))
}

// OUTPUT:
// converted json: {
//   "flags": {
//     "myBoolFlag": {
//       "state": "ENABLED",
//       "variants": {
//         "off": false,
//         "on": true
//       }
//     }
//   }
// }

A slightly modified example on Go playground: https://play.golang.com/p/4iCzr8UmEHT

Gotchas

Make sure you use "gopkg.in/yaml.v3" and not "gopkg.in/yaml.v2" because "gopkg.in/yaml.v2" Unmarshals the sub-maps to map[interface]interface{} instead of map[string]interface{} and json.Marshal fails because it doesn’t understand map[interface]interface{}