JSON (JavaScript Object Notation) is a simple data interchange format. Syntactically it resembles the objects and lists of JavaScript. It is most commonly used for communication between web back-ends and JavaScript programs running in the browser, but it is used in many other places, too. Its home page, json.org, provides a wonderfully clear and concise definition of the standard.
With the json package it's a snap to read and write JSON data from your Go programs.
Encoding
To encode JSON data we use the
Marshal
function.
func Marshal(v interface{}) ([]byte, error)
Given the Go data structure, Message
,
and an instance of Message
we can marshal a JSON-encoded version of m using json.Marshal
:
If all is well, err
will be nil
and b
will be a []byte
containing this JSON data:
b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
Only data structures that can be represented as valid JSON will be encoded:
map[string]T
(where T
is any Go type
supported by the json package).
Marshal
to go into an infinite loop.
nil
).
The json package only accesses the exported fields of struct types (those that begin with an uppercase letter). Therefore only the exported fields of a struct will be present in the JSON output.
Decoding
To decode JSON data we use the
Unmarshal
function.
func Unmarshal(data []byte, v interface{}) error
We must first create a place where the decoded data will be stored
{{code "/doc/progs/json1.go" `/var m Message/`}}
and call json.Unmarshal
, passing it a []byte
of JSON
data and a pointer to m
If b
contains valid JSON that fits in m
, after the
call err
will be nil
and the data from b
will have been stored in the struct m
, as if by an assignment
like:
How does Unmarshal
identify the fields in which to store the
decoded data? For a given JSON key "Foo"
, Unmarshal
will look through the destination struct's fields to find (in order of
preference):
"Foo"
(see the
Go spec for more on struct tags),
"Foo"
, or
"FOO"
or "FoO"
or some other
case-insensitive match of "Foo"
.
What happens when the structure of the JSON data doesn't exactly match the Go type?
{{code "/doc/progs/json1.go" `/"Food":"Pickle"/` `/STOP/`}}
Unmarshal
will decode only the fields that it can find in the
destination type. In this case, only the Name field of m will be populated,
and the Food field will be ignored. This behavior is particularly useful when
you wish to pick only a few specific fields out of a large JSON blob. It also
means that any unexported fields in the destination struct will be unaffected
by Unmarshal
.
But what if you don't know the structure of your JSON data beforehand?
Generic JSON with interface{}
The interface{}
(empty interface) type describes an interface with
zero methods. Every Go type implements at least zero methods and therefore
satisfies the empty interface.
The empty interface serves as a general container type:
{{code "/doc/progs/json2.go" `/var i interface{}/` `/STOP/`}}A type assertion accesses the underlying concrete type:
{{code "/doc/progs/json2.go" `/r := i/` `/STOP/`}}Or, if the underlying type is unknown, a type switch determines the type:
{{code "/doc/progs/json2.go" `/switch v/` `/STOP/`}} The json package usesmap[string]interface{}
and
[]interface{}
values to store arbitrary JSON objects and arrays;
it will happily unmarshal any valid JSON blob into a plain
interface{}
value. The default concrete Go types are:
bool
for JSON booleans,
float64
for JSON numbers,
string
for JSON strings, and
nil
for JSON null.
Decoding arbitrary data
Consider this JSON data, stored in the variable b
:
Without knowing this data's structure, we can decode it into an
interface{}
value with Unmarshal
:
At this point the Go value in f
would be a map whose keys are
strings and whose values are themselves stored as empty interface values:
To access this data we can use a type assertion to access f
's
underlying map[string]interface{}
:
We can then iterate through the map with a range statement and use a type switch to access its values as their concrete types:
{{code "/doc/progs/json3.go" `/for k, v/` `/STOP/`}}In this way you can work with unknown JSON data while still enjoying the benefits of type safety.
Reference Types
Let's define a Go type to contain the data from the previous example:
{{code "/doc/progs/json4.go" `/type FamilyMember/` `/STOP/`}} {{code "/doc/progs/json4.go" `/var m FamilyMember/` `/STOP/`}}
Unmarshaling that data into a FamilyMember
value works as
expected, but if we look closely we can see a remarkable thing has happened.
With the var statement we allocated a FamilyMember
struct, and
then provided a pointer to that value to Unmarshal
, but at that
time the Parents
field was a nil
slice value. To
populate the Parents
field, Unmarshal
allocated a new
slice behind the scenes. This is typical of how Unmarshal
works
with the supported reference types (pointers, slices, and maps).
Consider unmarshaling into this data structure:
type Foo struct { Bar *Bar }
If there were a Bar
field in the JSON object,
Unmarshal
would allocate a new Bar
and populate it.
If not, Bar
would be left as a nil
pointer.
From this a useful pattern arises: if you have an application that receives a few distinct message types, you might define "receiver" structure like
type IncomingMessage struct { Cmd *Command Msg *Message }
and the sending party can populate the Cmd
field and/or the
Msg
field of the top-level JSON object, depending on the type of
message they want to communicate. Unmarshal
, when decoding the
JSON into an IncomingMessage
struct, will only allocate the data
structures present in the JSON data. To know which messages to process, the
programmer need simply test that either Cmd
or Msg
is
not nil
.
Streaming Encoders and Decoders
The json package provides Decoder
and Encoder
types
to support the common operation of reading and writing streams of JSON data.
The NewDecoder
and NewEncoder
functions wrap the
io.Reader
and
io.Writer
interface types.
func NewDecoder(r io.Reader) *Decoder func NewEncoder(w io.Writer) *Encoder
Here's an example program that reads a series of JSON objects from standard
input, removes all but the Name
field from each object, and then
writes the objects to standard output:
Due to the ubiquity of Readers and Writers, these Encoder
and
Decoder
types can be used in a broad range of scenarios, such as
reading and writing to HTTP connections, WebSockets, or files.
References
For more information see the json package documentation. For an example usage of json see the source files of the jsonrpc package.