There are a number of easy to conflate issues going on here.
Output:
First and foremost is you're not specifying any particular output formatting.
Using fmt.Println to output data structures is really just for easy debugging, the formatting is pretty arbitrary you could get more reliably formatted output in correct Go if you used fmt.Printf("%#v
", i)
. The default Println outputs the equvelent of Printf's "%v".
To get output in a particular format (other then Go itself) you'll need to import a package that can generate that format. Luckily a few popular formats are included in the standard library. But before we can get to that there are a few other things to fix / understand.
Exports:
Capitalized members of a struct are exported lower case members are not. This means that "url"in your image structure MUST be capitalized or else packages such as encoding/json
will be unable to access the member to export it.
Anonymous Types:
Others emphasize creating explicit definitions for each of the structured data types in the overall structure, and I think that is generally good advice. However, it is also often silly to have so many one off type definitions floating around, so it is completely acceptable in the language to use inline anonymous structure definitions. Also a nice touch is that identically structured anonymous types are accepted as the same type unlike defined types.
Here's an, admittedly pathological, example of doing the above with anonymous structs.
i := struct{
Data interface{} `json:"data"`
}{
Data:struct{
Image interface{} `json:"image"`
} {
Image:struct{
Url string `json:"url"`
}{
Url:"test.jpg",
},
},
}
While this works it's pretty messy. But notice you can even add tags to the fields of anonymous types so json formatting translates as intended.
Another way to do it anonymously and avoid all this type
definition crazy is just use a map. Here's that example. Note however, that some Go cargo cultists will yell at you if they see you using map[string]interface{}
everywhere. Nevertheless there's actually nothing wrong with it either in practice or in philosophy.
j := map[string]interface{} {
"data":map[string]interface{}{
"image":map[string]interface{}{
"url":"test.jpg",
},
},
}
Generally however, you want to take advantage of what a typed language can give you. Strongly typed languages like Go are very good at finding otherwise subtile bugs early on.
And isn't this better looking:
type Object map[string]interface{}
// ...
j := Object{
"data": Object{
"image": Object{
"url":"test.jpg",
},
},
}
Once More With Encoding
Here's your program in a more idiomatic style. Which, not coincidentally, is also more readable in my opinion.
package main
import (
"fmt"
"encoding/json"
)
type data struct {
Image image `json:"image"`
}
type image struct {
Url string `json:"url"`
}
type images struct {
Data data `json:"data"`
}
func main() {
i := images{Data: data{Image: image{Url: "test.jpg"}}}
data, _ := json.Marshal(i)
fmt.Println(string(data))
}
Also note that while you must export the members to have them appear in the json, you do not have to export the types themselves.