Mohit Khare I'm a developer soul and a freelance writer from India who loves building and breaking stuff. Let's build something together!

Configuring JSON for Go

3 min read 1105

Working With Golang Json

Most modern applications require communication across multiple services, and JSON is one of the most popular notations for storing and transferring data across the web. In this article, we’ll explore working with JSON in Go, a popular open source language.

Let’s get started!

Introduction to JSON

JSON, or JavaScript Object Notation, is a popular text format for storing, sending, and receiving information. JSON is easy to write and understand due to its simple structure that is formatted as a key-value pair using ordered lists.

JSON is language-independent, meaning it can be used with any programming language. Many languages come with built-in support for JSON.

Let’s see what the JSON format looks like with an example! In the code block below, the JSON object represents a user on a web application:

{
  "firstname": "Mohit",
  "lastname": "Khare",
  "id": "mkfeuhrer",
  "age": "24",
  "gender": "male",
  "preferred_topics": ["startups", "books", "chess", "blogging"],
  "social_links": [
    {
      "site": "twitter",
      "url": "https://twitter.com/mkfeuhrer"
    }
  ]
} 

The JSON key must be a string based on how the JSON format schema is defined. However, the value can be a string, an object, or a list of strings or objects.

Reading JSON files in Go

Save the JSON object from the code block above to a file called user.json. We’ll use ReadFile from the ioutilpackage to read the JSON file and print the data:

package main
import (
    "fmt"
    "io/ioutil"
)
func ReadJSON(filename string) ([]byte, error) {
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        fmt.Println("Error reading user.json", err)
        return nil, err
    }
    fmt.Println("Success reading user.json")
    return data, nil
}
func main() {
    data, err := ReadJSON("user.json")
    if err != nil {
        return
    }
    fmt.Println("Content of user.json:")
    fmt.Println(string(data))
}

The output for the code above is as follows:

Success reading user.json
Content of user.json:
{
  "firstname": "Mohit",
  "lastname": "Khare",
  "id": "mkfeuhrer",
  "age": "24",
  "gender": "male",
  "preferred_topics": [
    "startups",
    "books",
    "chess"
  ],
  "social_links": [
    {
      "site": "twitter",
      "url": "https://twitter.com/mkfeuhrer"
    }
  ]
}

Decode JSON in Go structs

Now that we can read the JSON file, we’ll parse it into Go structs. You cannot perform Go operations directly on JSON data. Instead, you must map the JSON data to the Go struct, allowing it to perform other operations.

package json in Go provides the Unmarshal function, which helps us to parse data into structs:

We made a custom demo for .
No really. Click here to check it out.

func Unmarshal(data []byte, v interface{}) error  

Unmarshal requires that the data be in byte array to parse it to an interface. Let’s create a struct to read the user data defined above:

// parse social link object
type SocialLink struct {
        Site string `json:"site"`
        URL  string `json:"url"`
}

// parse user object
type User struct {
        Firstname       string      `json:"firstname"`
        Lastname        string      `json:"lastname"`
        ID              string      `json:"id"`
        Age             string      `json:"age"`
        Gender          string      `json:"gender"`
        PreferredTopics []string    `json:"preferred_topics"`
        SocialLinks     []SocialLink `json:"social_links"`
}

Now, we’ll parse JSON to this struct:

func DecodeJSON(data []byte, user *User) {
    err := json.Unmarshal(data, user)
    if err != nil {
        fmt.Println("Error parsing JSON", err)
    }
    fmt.Println(*user)
}

// We call this function with the data and user Object
var user User
DecodeJSON(data, &user)

Encode JSON from Go structs

We’d also like to write JSON data from our Go application, so let’s convert the structs we created to JSON data. Go’s package json provides the Marshal function to help encode structs to JSON data:

func Marshal(v interface{}) ([]byte, error)

Marshal requires an interface from which we’ll encode JSON data. Let’s encode our User object back to JSON:

func EncodeJSON(user *User) {
    data, err := json.Marshal(user)
    if err != nil {
        fmt.Println("Error parsing JSON", err)
    }
    fmt.Println(string(data))
}

// We call this function with the data and user Object
user := User {
    Firstname: "John",
    Lastname: "Doe",
    ID: "john",
    Age: "30",
    Gender: "male",
    SocialLinks: []SocialLink{
        {
            Site: "twitter",
            URL: "https://twitter.com/john",
        },
    },
}
EncodeJSON(data, &user)

The function above will print the JSON data:

{
  "firstname": "John",
  "lastname": "Doe",
  "id": "john",
  "age": "30",
  "gender": "male",
  "preferred_topics": null,
  "social_links": [
    {
      "site": "twitter",
      "url": "https://twitter.com/john"
    }
  ]
}

Notice carefully the preferred_topics field is null because our user object did not have a value assigned for this attribute. Now, let’s learn how we can skip empty fields.

JSON tags in Go

When we defined structs, we used a few JSON tags. Tags help us to control the key for attributes by omitting empty or null fields.

Let’s see an example of tags! In the code block below, we’ll define the Firstname attribute to use the "first name" key in JSON. We’ll omit PreferredTopics from the object if it is empty:

PreferredTopics []string `json:"preferred_topics,omitempty"`

We’ll simply ignore Age while we’re encoding/decoding JSON.

Age int `json:"-"`

We usually use omitempty when a value is optional within our structs. In our user example, we can manage if lastname of the user is not present, but we cannot add omitempty to id.

Your completed code will look like the following code block:

package main
import (
    "encoding/json"
    "fmt"
    "io/ioutil"
)
type SocialLink struct {
    Site string `json:"site"`
    URL  string `json:"url"`
}
type User struct {
    Firstname       string       `json:"firstname"`
    Lastname        string       `json:"lastname,omitempty"`
    ID              string       `json:"id"`
    Age             string       `json:"age,omitempty"`
    Gender          string       `json:"gender,omitempty"`
    PreferredTopics []string     `json:"preferred_topics,omitempty"`
    SocialLinks     []SocialLink `json:"social_links,omitempty"`
}
func ReadJSON(filename string) ([]byte, error) {
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        fmt.Println("Error reading user.json", err)
        return nil, err
    }
    fmt.Println("Success reading user.json")
    return data, nil
}
func DecodeJSON(data []byte, user *User) {
    err := json.Unmarshal(data, user)
    if err != nil {
        fmt.Println("Error parsing JSON", err)
    }
    fmt.Println(*user)
}
func EncodeJSON(user *User) {
    data, err := json.Marshal(user)
    if err != nil {
        fmt.Println("Error parsing JSON", err)
    }
    fmt.Println(string(data))
}
func main() {
    data, err := ReadJSON("user.json")
    if err != nil {
        return
    }
    fmt.Println("Content of user.json:")
    fmt.Println(string(data))
    var user User
    fmt.Println("\nDecode JSON data to user struct:")
    DecodeJSON(data, &user)
    // define new user
    user2 := User{
        Firstname: "John",
        Lastname:  "Doe",
        ID:        "john",
        Age:       "30",
        Gender:    "male",
        SocialLinks: []SocialLink{
            {
                Site: "twitter",
                URL:  "https://twitter.com/john",
            },
        },
    }
    fmt.Println("\nEncode struct to JSON:")
    EncodeJSON(&user2)
}  

Conclusion

In this tutorial, we learned how to read JSON files, encode and decode data to structs using the marshal and unmarshal functions, and define structs using tags.

Our example included simple fields for inputting a user’s profile information, but you can use the information from this tutorial to build a number of complex applications.

I hope you enjoyed the article and learned something useful!

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Mohit Khare I'm a developer soul and a freelance writer from India who loves building and breaking stuff. Let's build something together!

Leave a Reply