How I Merged and Validated Two JSON Files in Go

by @pheonix...June 24th, 2025
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Go has great support for reading files and decoding JSON using only the standard library. I wanted to learn how Go handles file I/O, JSON, and type safety. Here’s how I did it, what I learned, and some alternatives I found along the way.
featured image - How I Merged and Validated Two JSON Files in Go
Shridivya Sharma HackerNoon profile picture
0-item
1-item

When I started learning Go, my first real task was to merge two JSON files and validate the result. It sounded easy. It turned out to be a great way to learn how Go handles file I/O, JSON, maps, and type safety.

Here’s how I did it, what I learned, and some alternatives I found along the way.

The Task

  1. Read two JSON files.
  2. Merge them into a single structure.
  3. Validate the result to make sure certain fields exist and are of the correct type.
  4. Write the final JSON to a new file.

Step 1: Reading the JSON Files

Go has great support for reading files and decoding JSON using only the standard library.

data1, _ := ioutil.ReadFile("file1.json")
data2, _ := ioutil.ReadFile("file2.json")

var json1 map[string]interface{}
var json2 map[string]interface{}

json.Unmarshal(data1, &json1)
json.Unmarshal(data2, &json2)

Note: In newer versions of Go, you can use os.ReadFile instead of ioutil.ReadFile, since ioutil is deprecated.

Step 2: Merging the JSON Maps

I needed a function to merge two maps. If a key existed in both maps, the value from the second map should overwrite the first. If the value was a nested object, I needed to merge it recursively.

Here’s the function I wrote:

func mergeMaps(m1, m2 map[string]interface{}) map[string]interface{} {
    for k, v2 := range m2 {
        if v1, ok := m1[k]; ok {
            if v1Map, ok := v1.(map[string]interface{}); ok {
                if v2Map, ok := v2.(map[string]interface{}); ok {
                    m1[k] = mergeMaps(v1Map, v2Map)
                    continue
                }
            }
        }
        m1[k] = v2
    }
    return m1
}

This handled both flat and nested JSON structures correctly.

Step 3: Validating the JSON

Next, I wrote a simple validation function to check that certain fields were present and of the expected type. Since I wasn’t using a schema validator, I had to do manual checks.

func validateJSON(data map[string]interface{}) error {
    if _, ok := data["name"].(string); !ok {
        return fmt.Errorf("missing or invalid 'name' field")
    }

    if port, ok := data["port"]; !ok || reflect.TypeOf(port).Kind() != reflect.Float64 {
        return fmt.Errorf("missing or invalid 'port' field")
    }

    return nil
}

Note: When decoding JSON into interface{}, numbers are treated as float64 by default, which can be confusing at first.

Step 4: Writing the Result

Finally, I wrote the merged and validated JSON back to a file using pretty formatting.

resultBytes, _ := json.MarshalIndent(merged, "", "  ")
ioutil.WriteFile("merged_output.json", resultBytes, 0644)

It worked exactly as expected.

Alternatives: Using a Package to Merge JSON

Later, I discovered some packages make JSON merging easier. These are a few good ones:

1. mergo

mergo is a popular library for merging maps and structs in Go. It supports nested merges and lets you choose whether to overwrite values.

Install:

go get github.com/imdario/mergo

Example:

var a map[string]interface{}
var b map[string]interface{}

json.Unmarshal([]byte(`{"config": {"debug": false}}`), &a)
json.Unmarshal([]byte(`{"config": {"debug": true, "port": 8080}}`), &b)

mergo.Merge(&a, b, mergo.WithOverride)

Use this if you want clean, deep merging without writing recursive code.

2. json-patch (go-patch)

json-patch lets you apply JSON Patch operations. It’s more for diffing and applying structured updates, but still useful for working with JSON dynamically.

Install:

go get github.com/evanphx/json-patch

Use this if you’re working with patches or want to programmatically update JSON with control.

3. mapstructure

mapstructure helps decode dynamic maps into strongly typed structs. It’s not a merge tool by itself but works well after you merge JSON data and want to bind it to a Go struct.

Install:

go get github.com/mitchellh/mapstructure

Use this when you want structure and type safety after parsing JSON.

Final Thoughts

This task helped me learn a lot about how Go handles data, how JSON works under the hood, and why strong typing matters. Writing a merge function gave me control, but using libraries like mergo made the code more maintainable later.

If you're learning Go, I recommend starting with small tasks like this. You’ll get real experience with files, encoding, maps, and error handling, all while solving a practical problem.

It’s a small project, but one that taught me a lot.


Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks