Golang encoding/json
Conveniently, the builtin types are ready for json serialization/deserialization without any additional work.
Documentation
official docs https://pkg.go.dev/encoding/json@go1.18.3 intro https://go.dev/blog/json
Tutorials
cholys blog http://choly.ca/post/go-json-marshalling/
Deserializing
Builtins
// string, int var name string json.Unmarshal([]byte(`"vaderd"`), &name) fmt.Println(name) // vaderd // array, slice var items [2]string json.Unmarshal([]byte(`["abc", "def"]`), &items) fmt.Println(items) // [abc def]Arbitrary JSON
You can parse arbitrary json objects using
interface{}
.projects_json := []byte(`{"Projects": [{"Name": "a"}, {"Name": "b"}]}`) var projects interface{} json.Unmarshal(projects_json, &projects) projects_casted := projects.(map[string]interface{}) // type-assertion -- if type does not match, panics fmt.Println(projects_casted["Projects"]) // [map[Name:a] map[Name:b]]Json-Object to Struct
type User struct { id int Name string } var user User data := []byte(`{"id": 123, "Name": "vaderd"}`) json.Unmarshal(data, &user) fmt.Println(user.Name)Unlike the serialization behaviour, even un-exported fields will be set on the object.
You assume the JSON object knows what it wants set.type User struct { id int Name string } func (u *User) Id() int { return u.id } var user2 User data := []byte(`{"id": 123, "Name": "vaderd"}`) json.Unmarshal(data, &user2) fmt.Println(user.Id()) // 123Custom Deserialization
Serializing
Builtins
// string, int bytes, _ := json.Marshal("vaderd") fmt.Println(string(bytes)) // '"vaderd"' // array, slice names := []string{"maize", "sprout"} bytes, _ := json.Marshal(names) fmt.Println(string(bytes)) // '["maize", "sprout"]'Struct to Json-Object
Only exported fields will be serialized by default.
If you'd like to keep private fields, you can define aMarshalJSON()
method (see Custom Serialization below).type User struct { id int Name string } user := User{id: 1, Name: "will"} bytes, _ := json.Marshal(user) fmt.Println(string(bytes)) // '{"Name": "will"}'Custom Serialization
If you need more control over serialization, you can define a
MarshalJSON()
method.It's common to define an ad-hoc struct type to represent your JSON object.
You can use struct tags to assign different names to your fields when encoded in json.type User struct { id int Name string } func (u User) MarshalJSON() ([]byte, error) { return json.Marshal(&struct { Id int `json:"id"` // struct-tag alters the key within the encoded json obj Name string `json:"name"` }{ Id: u.id, Name: u.Name, }) } user := User{1, "will"} bytes, _ := json.Marshal(user) fmt.Println(string(bytes)) // '{"id": 1, "name": "will"}'If you're only changing some fields of a struct, you can inherit it, and override only the methods you want to change.
type User struct { id int Name string } func (u *User) MarshalJSON() ([]byte, error) { type Alias User return json.Marshal(&struct { Name string `json:"Name"` *Alias }{ Name: fmt.Sprintf("--%s--", u.Name), Alias: (*Alias)(u), }) } user := User{1, "will"} bytes, _ := json.Marshal(&user) fmt.Println(string(bytes)) // {"Name": "--will--"}Note that if you do this, you can't change the name of a field, or you'll end up with both fields
type User struct { id int Name string } func (u *User) MarshalJSON() ([]byte, error) { type Alias User return json.Marshal(&struct { Name string `json:"name"` *Alias }{ Name: fmt.Sprintf("--%s--", u.Name), Alias: (*Alias)(u), }) } user := User{1, "will"} bytes, _ := json.Marshal(&user) fmt.Println(string(bytes)) // {"Name": "--will--", "name": "will"}