How to work with JSON data in Go
Tags: go, tutorial, showdev, beginners
Published: 2019-10-03 13:03:18

Welcome to **Just Enough Go** ! This is the first in a series of articles about the [Go programming language](https://golang.org/) in which I will be covering some of the most commonly used [Go standard library packages](https://golang.org/pkg) 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](https://github.com/abhirockzz/just-enough-go)

I would be more than happy to take suggestions on specific Go topics which you would like to me cover! Feel free to [tweet](https://twitter.com/abhi_tweeter) or just drop a comment 😃

This article covers the [`encoding/json`](https://golang.org/pkg/encoding/json/) package which handles conversion between JSON and Go types (as per [RFC 7159](https://tools.ietf.org/html/rfc7159)). Let's jump right in!

![](https://media.giphy.com/media/UcK7JalnjCz0k/giphy-downsized.gif)

### 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 😃😃