Welcome to Just Enough Go ! This is the first in a series of articles about the Go programming language in which I will be covering some of the most commonly used Go standard library packages e.g. encoding/json
, io
, net/http
, sync
etc. I plan to keep these relatively short and example driven.
the code is available in this GitHub repo
I would be more than happy to take suggestions on specific Go topics which you would like to me cover! Feel free to tweet or just drop a comment ๐
This article covers the encoding/json
package which handles conversion between JSON and Go types (as per RFC 7159). Let's jump right in!
Converting a Go type into JSON
Marshal
A common option is to use the Marshal
function whose signature is:
func Marshal(v interface{}) ([]byte, error)
Here is an example:
func main() {
profile := Profile{Email: "abhirockzz@gmail.com", Username: "abhirockzz", Blogs: []Blog{
Blog{BlogName: "devto", URL: "https://dev.to/abhirockzz/"},
Blog{BlogName: "medium", URL: "https://medium.com/@abhishek1987/"},
}}
jsonData, err := json.Marshal(&myprofile)
//jsonData, err := json.MarshalIndent(&profile, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(jsonData))
}
you can use
MarshalIndent
(commented) to indent the JSON output
Encoder
While Marshal
deals in byte arrays ([]byte
), an Encoder
is generic and lets you work with an io.Writer
which you can define to be the sink for JSON data i.e. you can specify any type which implements the io.Writer
interface e.g. this could be standard out (os.Stdout
), or an HTTP response (http.ResponseWriter
), etc.
func main() {
profile := Profile{Email: "abhirockzz@gmail.com", Username: "abhirockzz", Blogs: []Blog{
Blog{BlogName: "devto", URL: "https://dev.to/abhirockzz/"},
Blog{BlogName: "medium", URL: "https://medium.com/@abhishek1987/"},
}}
encoder := json.NewEncoder(os.Stdout)
err := encoder.Encode(&profile)
if err != nil {
panic(err)
}
}
Use NewEncoder
to specify the io.Writer
. When you call Encode
, the conversion takes place and the JSON is writer to io.Writer
you specified.
Here is an example of how it would work with an HTTP response:
func main() {
profile := Profile{Email: "abhirockzz@gmail.com", Username: "abhirockzz", Blogs: []Blog{
Blog{BlogName: "devto", URL: "https://dev.to/abhirockzz/"},
Blog{BlogName: "medium", URL: "https://medium.com/@abhishek1987/"},
}}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
encoder := json.NewEncoder(w)
err := encoder.Encode(&profile)
if err != nil {
panic(err)
}
})
http.ListenAndServe(":8080", nil)
}
Converting JSON data to a Go type
Unmarshal
Given JSON in form of a byte array, Unmarshal
stores the JSON parsing result to a pointer of the Go data type you specify (typically a struct
)
func Unmarshal(data []byte, v interface{}) error
Here is a simple example:
func main() {
jsonData := `{"email":"abhirockzz@gmail.com","username":"abhirockzz","blogs":[{"name":"devto","url":"https://dev.to/abhirockzz/"},{"name":"medium","url":"https://medium.com/@abhishek1987/"}]}`
var profile Profile
err := json.Unmarshal([]byte(jsonData), &profile)
if err != nil {
panic(err)
}
...
}
Decoder
Decoder
provides a generic way of unmarshalling JSON data by allowing you to specify the source of JSON input in the form of an io.Reader
as opposed to a byte array.
func main() {
jsonData := `{"email":"abhirockzz@gmail.com","username":"abhirockzz","blogs":[{"name":"devto","url":"https://dev.to/abhirockzz/"},{"name":"medium","url":"https://medium.com/@abhishek1987/"}]}`
jsonDataReader := strings.NewReader(jsonData)
decoder := json.NewDecoder(jsonDataReader)
var profile Profile
err := decoder.Decode(&profile)
if err != nil {
panic(err)
}
...
}
We start by creating an io.Reader
from the JSON string
data using a shortcut strings.NewReader
. We can then instantiate the decoder using NewDecoder
and simply use decode
with a pointer to the Profile
struct to which the result is stored
That's all for this blog! Stay tuned for more and don't forget to like and follow ๐๐
Top comments (1)
I think this article is omitting a critical part: The definition of
Profile
. A reader that doesn't know how to defineProfile
will not be able to reproduce this. Looking at your github code will probably help, but the key to json handling in Go withstructs
is in the annotations on thestruct
-- which is not mentioned here.Note:
Profile
could also be amap[string]interface{}
(which I'd not recommend to use!!).