7.2 JSON

JSON (JavaScript Object Notation) is a lightweight data exchange language which is based on text description. Its advantages include being self-descriptive, easy to understand, etc. Even though it is a subset of JavaScript, JSON uses a different text format, the result being that it can be considered as an independent language. JSON bears similarity to C-family languages.

The biggest difference between JSON and XML is that XML is a complete markup language, whereas JSON is not. JSON is smaller and faster than XML, therefore it's much easier and quicker to parse in browsers, which is one of the reasons why many open platforms choose to use JSON as their data exchange interface language.

Since JSON is becoming more and more important in web development, let's take a look at the level of support Go has for JSON. You'll find that Go's standard library has very good support for encoding and decoding JSON.

In the above example, we defined a corresponding structs in Go for our JSON, using slice for an array of JSON objects and field name as our JSON keys. But how does Go know which JSON object corresponds to which specific struct filed? Suppose we have a key called Foo in JSON. How do we find its corresponding field?

If there are still not matches look for something like FOO or FoO, ignoring case sensitivity.

You may have noticed that all fields that are going to be assigned should be exported, and Go only assigns fields that can be found, ignoring all others. This can be useful if you need to deal with large chunks of JSON data but you only a specific subset of it; the data you don't need can easily be discarded.

Parse to interface

When we know what kind of JSON to expect in advance, we can parse it to a specific struct. But what if we don't know?

We know that an interface{} can be anything in Go, so it is the best container to save our JSON of unknown format. The JSON package uses map[string]interface{} and []interface{} to save all kinds of JSON objects and arrays. Here is a list of JSON mapping relations:

As you can see, we can now parse JSON of an unknown format through interface{} and type assertion.

The above example is the official solution, but type asserting is not always convenient. So, I recommend an open source project called simplejson, created and maintained by bitly. Here is an example of how to use this project to deal with JSON of an unknown format:

As you know, all field names are capitalized, but if you want your JSON key names to start with a lower case letter, you should use struct tags. Otherwise, Go will not produce data for internal fields.

The Marshal function only returns data when it has succeeded, so here are some points we need to keep in mind:

JSON only supports strings as keys, so if you want to encode a map, its type has to be map[string]T, where T is the type in Go.

Types like channel, complex types and functions are not capable of being encoded to JSON.

Do not try to encode cyclic data, it leads to an infinite recursion.

If the field is a pointer, Go outputs the data that it points to, or else outputs null if it points to nil.

In this section, we introduced how to decode and encode JSON data in Go. We also looked at one third-party project called simplejson which is useful for parsing JSON or unknown format. These are all useful concepts for developing web applications in Go.