Creating JSON representation from Go struct - json

I am trying to create a JSON string from a struct:
package main
import "fmt"
func main() {
type CommentResp struct {
Id string `json: "id"`
Name string `json: "name"`
}
stringa := CommentResp{
Id: "42",
Name: "Foo",
}
fmt.Println(stringa)
}
This code prints {42 foo}, but I expected {"Id":"42","Name":"Foo"}.

What you are printing is fmt's serialization of the CommentResp struct. Instead, you want to do is use json.Marshal to get the encoded JSON repsentation:
data, err := json.Marshal(stringa)
if err != nil {
// Problem encoding stringa
panic(err)
}
fmt.Println(string(data))
https://play.golang.org/p/ogWKQ3M6tb
Also, your json struct tags are not valid; there cannot be a space between : and the quoted string:
type CommentResp struct {
Id string `json:"id"`
Name string `json:"name"`
}
https://play.golang.org/p/eQiyTk6-vQ

Related

hh:mm:ss to time.Time while parsing from JSON in Go

I have a struct that I can't change and an array of these structs in a separate JSON file.
I could have parsed data from JSON file easily, but there are mismatched types in same fields:
(main.go)
import "time"
type SomeType struct {
name string `json: "name"`
time time.Time `json: "someTime"`
}
(someData.json)
[
{
"name": "some name",
"someTime": "15:20:00"
},
{
"name": "some other name",
"someTime": "23:15:00"
}
]
If "time" field was a type of a string, I would simply use json.Unmarshal and parse all of the data from json into []SomeType, but since types mismatch, I can't find a way to do it correctly.
You should add the UnmarshalJSON method to your struct
type SomeType struct {
Name string `json:"name"`
Time time.Time `json:"someTime"`
}
func (st *SomeType) UnmarshalJSON(data []byte) error {
type parseType struct {
Name string `json:"name"`
Time string `json:"someTime"`
}
var res parseType
if err := json.Unmarshal(data, &res); err != nil {
return err
}
parsed, err := time.Parse("15:04:05", res.Time)
if err != nil {
return err
}
now := time.Now()
st.Name = res.Name
st.Time = time.Date(now.Year(), now.Month(), now.Day(), parsed.Hour(), parsed.Minute(), parsed.Second(), 0, now.Location())
return nil
}
GoPlay
I think you should define a custom time type, with a custom unmarshaller as follows:
type CustomTime struct {
time.Time
}
func (t *CustomTime) UnmarshalJSON(b []byte) error {
formattedTime, err := time.Parse(`"15:04:05"`, string(b))
t.Time = formattedTime
return err
}
And have another struct, which is basically the exact struct you have, instead it uses your custom time type rather than the original struct which uses time.Time:
type SameTypeWithDifferentTime struct {
Name string `json:"name"`
SomeTime CustomTime `json:"someTime"`
}
func (s SameTypeWithDifferentTime) ToOriginal() SomeType {
return SomeType {
Name: s.Name,
SomeTime: s.SomeTime.Time,
}
}
The rest of the process is pretty straight forward, you just deserialize your json to the new type, and use ToOriginal() receiver function to convert it to your original struct. Another point to mention here is that your not exporting your struct fields.

How to serialize a dictionary in golang

I try to replicate this body form in order to use it in a request:
{"Responses":[{"type":"DROP_DOWN","value":"0"}]}
so what im doing is :
type FruitBasket struct {
Name5 []string `json:"Responses"`
}
form := payload{
Name5: []string{"type", "value"},
}
jsonData, err := json.Marshal(form)
fmt.Println(string(jsonData))
But i can't find a way to complete the body in the brackets
You need to use the Unmarshal function from "encoding/json" package and use a dummy struct to extract the slice fields
// You can edit this code!
// Click here and start typing.
package main
import (
"encoding/json"
"fmt"
)
func main() {
str := `{"Responses":[{"type":"DROP_DOWN","value":"0"}]}`
type Responses struct {
Type string `json:"type"`
Value string `json:"value"`
}
// add dummy struct to hold responses
type Dummy struct {
Responses []Responses `json:"Responses"`
}
var res Dummy
err := json.Unmarshal([]byte(str), &res)
if err != nil {
panic(err)
}
fmt.Println("%v", len(res.Responses))
fmt.Println("%s", res.Responses[0].Type)
fmt.Println("%s", res.Responses[0].Value)
}
JSON-to-go is a good online resource to craft Go date types for a particular JSON schema.
Pasting your JSON body & extracting out the nested types you could use the following types to generate the desired JSON schema:
// types to produce JSON:
//
// {"Responses":[{"type":"DROP_DOWN","value":"0"}]}
type FruitBasket struct {
Response []Attr `json:"Responses"`
}
type Attr struct {
Type string `json:"type"`
Value string `json:"value"`
}
to use:
form := FruitBasket{
Response: []Attr{
{
Type: "DROP_DOWN",
Value: "0",
},
}
}
jsonData, err := json.Marshal(form)
working example: https://go.dev/play/p/SSWqnyVtVhF
output:
{"Responses":[{"type":"DROP_DOWN","value":"0"}]}
Your struct is not correct. Your title want dictionary, but you write an array or slice of string.
Change your FruitBasket struct from this:
type FruitBasket struct {
Name5 []string `json:"Responses"`
}
to this
type FruitBasket struct {
Name5 []map[string]interface{} `json:"Responses"`
}
map[string]interface{} is dictionary in go
here's the playground https://go.dev/play/p/xRSDGdZYfRN

How to navigate a nested json with unknown structure in Go?

I am trying to parse and get selected data from a deep nested json data in Go Lang. I'm having issues navigating through the structure and accessing the data. The data is too deep and complex to be parsed with a-priori known structures in Go.
Here is the URL of the file:
-https://www.data.gouv.fr/api/1/datasets/?format=csv&page=0&page_size=20
I did some parsing with map interfaces and using a json string:
resultdata := map[string]interface {}
json.Unmarshal([]byte(inputbytestring), &resultdata) //Inputstring is the string containing the JSON data of the above URL
The problem:
How can turn resultdata into a map (of strings), so I can use methods available for maps?
The JSON data is nested and has several levels. How is it possible to access the lower level JSON fields? is it possible to unmarshal the data recursively?
Once you have data as a map[string]interface{}, you can use type assertions to get to the lower levels of data.
There's a good explanation here of how to do this at https://blog.golang.org/json-and-go
Here's an example to get you most of the way:
https://play.golang.org/p/P8cGP1mTDmD
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
jsonData := `{
"string": "string_value",
"number": 123.45,
"js_array": ["a", "b", "c"],
"integer": 678,
"subtype": {
"number_array": [1, 2, 3]
}
}`
m := map[string]interface{}{}
err := json.Unmarshal([]byte(jsonData), &m)
if err != nil {
log.Fatal(err)
}
for key, value := range m {
switch v := value.(type) {
case int:
fmt.Printf("Key: %s, Integer: %d\n", key, v)
case float64:
fmt.Printf("Key: %s, Float: %v\n", key, v)
case string:
fmt.Printf("Key: %s, String: %s\n", key, v)
case map[string]interface{}:
fmt.Printf("Key: %s, Subtype: %+v\n", key, v)
case []interface{}:
//TODO: Read through each item in the interface and work out what type it is.
fmt.Printf("Key: %s, []interface: %v\n", key, v)
default:
fmt.Printf("Key: %s, unhandled type: %+v\n", key, v)
}
}
}
Alternatively https://mholt.github.io/json-to-go/ does a decent job of turning examples of JSON data into Go structs that can be used for marshalling.
Putting the example in, I get something that isn't too bad.
type AutoGenerated struct {
Data []struct {
Acronym interface{} `json:"acronym"`
Badges []interface{} `json:"badges"`
CreatedAt string `json:"created_at"`
Deleted interface{} `json:"deleted"`
Description string `json:"description"`
Extras struct {
} `json:"extras"`
Frequency string `json:"frequency"`
FrequencyDate interface{} `json:"frequency_date"`
ID string `json:"id"`
LastModified string `json:"last_modified"`
LastUpdate string `json:"last_update"`
License string `json:"license"`
Metrics struct {
Discussions int `json:"discussions"`
Followers int `json:"followers"`
Issues int `json:"issues"`
NbHits int `json:"nb_hits"`
NbUniqVisitors int `json:"nb_uniq_visitors"`
NbVisits int `json:"nb_visits"`
Reuses int `json:"reuses"`
Views int `json:"views"`
} `json:"metrics"`
Organization struct {
Acronym string `json:"acronym"`
Class string `json:"class"`
ID string `json:"id"`
Logo string `json:"logo"`
LogoThumbnail string `json:"logo_thumbnail"`
Name string `json:"name"`
Page string `json:"page"`
Slug string `json:"slug"`
URI string `json:"uri"`
} `json:"organization"`
Owner interface{} `json:"owner"`
Page string `json:"page"`
Private bool `json:"private"`
Resources []struct {
Checksum struct {
Type string `json:"type"`
Value string `json:"value"`
} `json:"checksum"`
CreatedAt string `json:"created_at"`
Description interface{} `json:"description"`
Extras struct {
} `json:"extras"`
Filesize int `json:"filesize"`
Filetype string `json:"filetype"`
Format string `json:"format"`
ID string `json:"id"`
LastModified string `json:"last_modified"`
Latest string `json:"latest"`
Metrics struct {
NbHits int `json:"nb_hits"`
NbUniqVisitors int `json:"nb_uniq_visitors"`
NbVisits int `json:"nb_visits"`
Views int `json:"views"`
} `json:"metrics"`
Mime string `json:"mime"`
PreviewURL string `json:"preview_url"`
Published string `json:"published"`
Title string `json:"title"`
Type string `json:"type"`
URL string `json:"url"`
} `json:"resources"`
Slug string `json:"slug"`
Spatial interface{} `json:"spatial"`
Tags []interface{} `json:"tags"`
TemporalCoverage interface{} `json:"temporal_coverage"`
Title string `json:"title"`
URI string `json:"uri"`
} `json:"data"`
Facets struct {
Format [][]interface{} `json:"format"`
} `json:"facets"`
NextPage string `json:"next_page"`
Page int `json:"page"`
PageSize int `json:"page_size"`
PreviousPage interface{} `json:"previous_page"`
Total int `json:"total"`
}
If you want inline decode of nested data for quick uses follow the below method:
myJsonData := `{
"code": "string_code",
"data": {
"id": 123,
"user": {
"username": "my_username",
"age": 30,
"posts": [ "post1", "post2"]
}
}
}`
Let's say you have the above nested and unknown JSON data that want to be read and parsed, first read that intomap[string]interface{}:
m := map[string]interface{}{}
err := json.Unmarshal([]byte(myJsonData), &m)
if err != nil {
log.Fatal(err)
}
Now if you want to access code
fmt.Println(m["code"])
For id in nested data block of JSON:
fmt.Println(m["data"].(map[string]interface{})["id"].(float64))
For username in the second level nested user block of JSON:
fmt.Println(m["data"].(map[string]interface{})["user"].(map[string]interface{})["username"].(string))
For age in the second level nested user block of JSON:
fmt.Println(m["data"].(map[string]interface{})["user"].(map[string]interface{})["age"].(float64))
For post1 in the third level nested posts block of JSON:
fmt.Println(m["data"].(map[string]interface{})["user"].(map[string]interface{})["posts"].([]interface{})[0].(string))
Please check the example in playground

json: cannot unmarshal array into Go value of type main.Data

Json is -
{
"apiAddr":"abc",
"data":
[
{
"key":"uid1",
"name":"test",
"commandList":["dummy cmd"],
"frequency":"1",
"deviceList":["dev1"],
"lastUpdatedBy": "user",
"status":"Do something"
}
]
}
And the code to unmarshall is -
type Data struct {
APIAddr string `json:"apiAddr"`
Data []Template `json:"data"`
}
type Template struct {
Key string `json:"key"`
Name string `json:"name"`
CommandList []string `json:"commandList"`
Frequency string `json:"frequency"`
DeviceList []string `json:"deviceList"`
LastUpdatedBy string `json:"lastUpdatedBy"`
Status string `json:"status"`
}
raw, err := ioutil.ReadFile(*testFile)
if err != nil {
return
}
var testTemplates Data
err = json.Unmarshal(raw, &testTemplates)
if err != nil {
return
}
where testFile is the json file.
I am getting this error
json: cannot unmarshal array into Go value of type main.Data.
Looking at the existing questions in stackoverflow, looks like I am doing all right.Anyone?
Made a few modification and Unmarshaling worked just fine.
package main
import (
"encoding/json"
"fmt"
)
var raw = ` {
"apiAddr":"abc",
"data":
[
{
"key":"uid1",
"name":"test",
"commandList":["dummy cmd"],
"frequency":"1",
"deviceList":["dev1"],
"lastUpdatedBy": "user",
"status":"Do something"
}
]
}`
func main() {
var testTemplates Data
err := json.Unmarshal([]byte(raw), &testTemplates)
if err != nil {
return
}
fmt.Println("Hello, playground", testTemplates)
}
type Data struct {
APIAddr string `json:"apiAddr"`
Data []Template `json:"data"`
}
type Template struct {
Key string `json:"key"`
Name string `json:"name"`
CommandList []string `json:"commandList"`
Frequency string `json:"frequency"`
DeviceList []string `json:"deviceList"`
LastUpdatedBy string `json:"lastUpdatedBy"`
Status string `json:"status"`
}
You can run it in Playground as well: https://play.golang.org/p/TSmUnFYO97-

Create a struct from a byte array

I use the json.Marshal interface to accept a map[string]interface{} and convert it to a []byte (is this a byte array?)
data, _ := json.Marshal(value)
log.Printf("%s\n", data)
I get this output
{"email_address":"joe#me.com","street_address":"123 Anywhere Anytown","name":"joe","output":"Hello World","status":1}
The underlying bytes pertain to the struct of the below declaration
type Person struct {
Name string `json:"name"`
StreetAddress string `json:"street_address"`
Output string `json:"output"`
Status float64 `json:"status"`
EmailAddress string `json:"email_address",omitempty"`
}
I'd like to take data and generate a variable of type Person struct
How do I do that?
You use json.Unmarshal:
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
StreetAddress string `json:"street_address"`
Output string `json:"output"`
Status float64 `json:"status"`
EmailAddress string `json:"email_address",omitempty"`
}
func main() {
data := []byte(`{"email_address":"joe#me.com","street_address":"123 Anywhere Anytown","name":"joe","output":"Hello World","status":1}`)
var p Person
if err := json.Unmarshal(data, &p); err != nil {
panic(err)
}
fmt.Printf("%#v\n", p)
}
Output:
main.Person{Name:"joe", StreetAddress:"123 Anywhere Anytown", Output:"Hello World", Status:1, EmailAddress:"joe#me.com"}