Try it yourself with our free Json Yaml Converter tool — runs entirely in your browser, no signup needed.

How to Convert JSON to YAML in Go

How to Convert JSON to YAML in Go

Converting JSON to YAML is a common task in data processing and configuration management. JSON (JavaScript Object Notation) is a lightweight data interchange format, while YAML (YAML Ain't Markup Language) is a human-readable serialization format. In Go, converting between these formats is essential for tasks like configuration file parsing, data exchange, and logging. In this article, we will explore how to convert JSON to YAML in Go, covering the basics, edge cases, and performance tips.

Quick Example

Here's a minimal example that demonstrates how to convert a JSON string to YAML:

package main

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

func main() {
	jsonStr := `{"name": "John", "age": 30}`
	var jsonData map[string]interface{}
	json.Unmarshal([]byte(jsonStr), &jsonData)

	yamlStr, err := yaml.Marshal(jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(yamlStr))
}

This code converts a JSON string to a map[string]interface{} using the encoding/json package, and then marshals the map to YAML using the gopkg.in/yaml.v3 package.

Step-by-Step Breakdown

Let's break down the code:

  1. We import the necessary packages: encoding/json for JSON parsing and gopkg.in/yaml.v3 for YAML marshaling.
  2. We define a JSON string jsonStr containing a simple object with two fields: name and age.
  3. We create a map[string]interface{} variable jsonData to store the parsed JSON data.
  4. We use json.Unmarshal to parse the JSON string into the jsonData map.
  5. We marshal the jsonData map to YAML using yaml.Marshal, which returns a byte slice containing the YAML data.
  6. We print the resulting YAML string.

Handling Edge Cases

Empty/Null Input

When dealing with empty or null input, we need to handle the error cases properly:

func main() {
	jsonStr := ""
	var jsonData map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &jsonData)
	if err != nil {
		fmt.Println(err) // prints "unexpected end of JSON input"
		return
	}
	// ...
}

In this case, json.Unmarshal returns an error indicating that the input is invalid.

Invalid Input

For invalid input, we can use the json.Valid function to check if the input is a valid JSON:

func main() {
	jsonStr := "{ invalid json }"
	if !json.Valid([]byte(jsonStr)) {
		fmt.Println("invalid JSON input")
		return
	}
	// ...
}

Large Input

When dealing with large input, we can use the json.Decoder type to stream the JSON data:

func main() {
	jsonStr := `{"large": "data"}` // large JSON data
	dec := json.NewDecoder(strings.NewReader(jsonStr))
	var jsonData map[string]interface{}
	err := dec.Decode(&jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	// ...
}

Unicode/Special Characters

YAML supports Unicode characters, but we need to ensure that our input is properly encoded:

func main() {
	jsonStr := `{"name": "John \u2605"}` // Unicode character
	var jsonData map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	yamlStr, err := yaml.Marshal(jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(yamlStr)) // prints YAML with Unicode character
}

Common Mistakes

1. Not Handling Errors

func main() {
	jsonStr := `{"name": "John"`
	var jsonData map[string]interface{}
	json.Unmarshal([]byte(jsonStr), &jsonData) // ignore error
	// ...
}

Corrected code:

func main() {
	jsonStr := `{"name": "John"`
	var jsonData map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	// ...
}

2. Not Checking for Valid JSON

func main() {
	jsonStr := "{ invalid json }"
	var jsonData map[string]interface{}
	json.Unmarshal([]byte(jsonStr), &jsonData) // ignore invalid input
	// ...
}

Corrected code:

func main() {
	jsonStr := "{ invalid json }"
	if !json.Valid([]byte(jsonStr)) {
		fmt.Println("invalid JSON input")
		return
	}
	// ...
}

3. Not Encoding Unicode Characters

func main() {
	jsonStr := `{"name": "John \u2605"}` // Unicode character
	var jsonData map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	yamlStr, err := yaml.Marshal(jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(yamlStr)) // prints YAML without Unicode character
}

Corrected code:

func main() {
	jsonStr := `{"name": "John \u2605"}` // Unicode character
	var jsonData map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	yamlStr, err := yaml.Marshal(jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(yamlStr)) // prints YAML with Unicode character
}

Performance Tips

1. Use Streaming Decoders

When dealing with large input, use the json.Decoder type to stream the JSON data:

func main() {
	jsonStr := `{"large": "data"}` // large JSON data
	dec := json.NewDecoder(strings.NewReader(jsonStr))
	var jsonData map[string]interface{}
	err := dec.Decode(&jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	// ...
}

2. Use Buffering

When marshaling YAML data, use buffering to improve performance:

func main() {
	jsonStr := `{"name": "John"}`
	var jsonData map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	var buf bytes.Buffer
	err = yaml.NewEncoder(&buf).Encode(jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(buf.String()) // prints YAML data
}

3. Avoid Unnecessary Allocations

Avoid unnecessary allocations when working with large input:

func main() {
	jsonStr := `{"large": "data"}` // large JSON data
	var jsonData map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	// avoid unnecessary allocation
	yamlStr, err := yaml.Marshal(jsonData)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(yamlStr)) // prints YAML data
}

FAQ

Q: What is the difference between JSON and YAML?

A: JSON is a lightweight data interchange format, while YAML is a human-readable serialization format.

Q: How do I handle invalid JSON input?

A: Use the json.Valid function to check if the input is a valid JSON.

Q: How do I handle large input?

A: Use the json.Decoder type to stream the JSON data.

Q: How do I encode Unicode characters?

A: Use the unicode package to properly encode Unicode characters.

Q: What are some common mistakes when converting JSON to YAML in Go?

A: Not handling errors, not checking for valid JSON, and not encoding Unicode characters.

AI agent tools available. The CodeTidy MCP Server gives Claude, Cursor, and other AI agents access to 60+ developer tools. One command: npx @codetidy/mcp