Working with json

Hello,
I started learning Go recently, and I wanted to make sure that I understood correctly that the only way to work with json format is by Marshal and unmarshal ?

coming from less strict languages like php/js where I don’t need to pre-define/know the structure of the json i’m going to get this left me very unsure.

I got to work with many 3rd patry api’s where the response is unpredictable… sometimes the structure changes depending on if the operation was successful or not, sometimes the api is written by baboons and i’m prepared for any response… sometimes devs change the api without letting anyone know (int can be suddenly a string … or a bigger int)

How do this work with Go? how can i work with such cases when i need to know 1000% of the time the exact response?
even in the most simple example I tried where i was the creator of the json string it was a pain to define 4 structs and nest them just to access 1 value from a string :fearful:

1 Like

JSON has to be marshaled and unmarshaled no matter the language because it is a serialization format. The fundamental problem is the difference between type systems of go and json. Here are some tools to help out:

If you just need to extract some values, https://github.com/tidwall/gjson will help. Of course, if you need most of the data it is better to unmarshal the whole thing.

https://mholt.github.io/json-to-go/ or https://github.com/ChimeraCoder/gojson can help generate the go data structure from some json input. Use the output to quick start whatever you are doing.

json.RawMessage can be used to defer the unmarshaling of a nested type until you figure out what it should be. This is useful when a response envelope tells you what type the contents is.

For dealing with apis written by baboons, all you can do is embrace interface{} and type switches. I usually try to place interface{} as deep into a data structure as I can get away with. This starts by using []interface or map[string]interface{} if the top level object is an array or an object.

On having to know the structure of the json … you always had to know what was there to do anything with it. The benefit of declaring the structure is that the code self-documents what the structure is. I always found it frustrating to have to trace back through some code to figure out what could be in a data structure. I mean, I can’t do anything with the data if I don’t know what it is, and then to have it’s definition spread throughout the source… :unamused:

Anyway, if you want some help or want to know if there is a better way to handle a specific situation, please post an example of the json and tell us what you are trying to do with it. We are happy to help.

3 Likes

Thank you! I will try all your advices

also try this simple example to understand how it works:

  • nested json
  • array in json
  • read json from file
  • numeric field in json

package main

import (
	"encoding/json"
	"log"
	"os"
)

type Record struct {
	A int
	B string
}

type Config struct {
	Ip       string `json:"ip"`
	Port     int    `json:"port,string,omitempty"`
	Database struct {
		Engine   string `json:"engine"`
		Ip       string `json:"ip"`
		Port     int    `json:"port,string,omitempty"`
		User     string `json:"user"`
		Password string `json:"password"`
		Name     string `json:"name"`
	} `json:"database"`
	ArrayExample []Record `json:"array"`
}

var c Config

func main() {
	f, err := os.Open("conf.json")
	if err != nil {
		log.Println(err.Error())
		return
	}
	if err := json.NewDecoder(f).Decode(&c); err != nil {
		log.Println(err.Error())
		return
	}
	log.Println(c, c.Port, c.Database.Ip)
	for k, v := range c.ArrayExample {
		log.Println(k, v.A, v.B)
	}
}

conf.json file:

{
    "ip": "",
    "port": 8080,
    "database": {
        "engine": "mysql",
        "ip": "192.168.1.2",
        "port": "3306",
        "user": "root",
        "password": "1234"
    },
    "array": [
        {
            "a": 1,
            "b": "aaa"
        },
        {
            "a": 2,
            "b": "bbb"
        }
    ]
}

remember to verify your json otherwise unmarshall will fail.

2 Likes

If you only want a few values from a “noisy” json, look at the various xpath-like programs. For example, I might write //universe/planet/timelord=doctor to find a construct named “planet” in a universe of json, such that there was a timelord named doctor on it.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.