I am trying to convert a Go struct to JSON using the json package but all I get is {}. I am certain it is something totally obvious but I don't see it.
package main
import (
"fmt"
"encoding/json"
)
type User struct {
name string
}
func main() {
user := &User{name:"Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Printf("Error: %s", err)
return;
}
fmt.Println(string(b))
}
Then when I try to run it I get this:
$ 6g test.go && 6l -o test test.6 && ./test
{}
You need to export the User.name field so that the json package can see it. Rename the name field to Name.
package main
import (
"fmt"
"encoding/json"
)
type User struct {
Name string
}
func main() {
user := &User{Name: "Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(b))
}
Output:
{"Name":"Frank"}
Related issue:
I was having trouble converting struct to JSON, sending it as response from Golang, then, later catch the same in JavaScript via Ajax.
Wasted a lot of time, so posting solution here.
In Go:
// web server
type Foo struct {
Number int `json:"number"`
Title string `json:"title"`
}
foo_marshalled, err := json.Marshal(Foo{Number: 1, Title: "test"})
fmt.Fprint(w, string(foo_marshalled)) // write response to ResponseWriter (w)
In JavaScript:
// web call & receive in "data", thru Ajax/ other
var Foo = JSON.parse(data);
console.log("number: " + Foo.number);
console.log("title: " + Foo.title);
This is an interesting question, it is very easy using the new go versions. You should do this:
package main
import (
"fmt"
"encoding/json"
)
type User struct {
Name string `json:"name"`
}
func main() {
user := &User{name:"Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Printf("Error: %s", err)
return;
}
fmt.Println(string(b))
}
Change this name to Name.
You can define your own custom MarshalJSON and UnmarshalJSON methods and intentionally control what should be included, ex:
package main
import (
"fmt"
"encoding/json"
)
type User struct {
name string
}
func (u *User) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Name string `json:"name"`
}{
Name: "customized" + u.name,
})
}
func main() {
user := &User{name: "Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(b))
}
Struct values encode as JSON objects. Each exported struct field becomes
a member of the object unless:
the field's tag is "-", or
the field is empty and its tag specifies the "omitempty" option.
The empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero. The object's default key string is the struct field name but can be specified in the struct field's tag value. The "json" key in the struct field's tag value is the key name, followed by an optional comma and options.
Related
i cannot parse the json value i am sending a playground link
Any idea about that? here is the link and codes
https://play.golang.org/p/qhZpS_-618s
package main
import (
"encoding/json"
"fmt"
//mapstructure "github.com/mitchellh/mapstructure"
)
type presence struct{
id string
m_type string
deny string
}
type jsonHandler struct {
name string
dat map[string]interface{}
}
func main() {
s := `["Presence",{"id":"905356870666#c.us","type":"unavailable","deny":true}]`
data := jsonHandler{}
json.Unmarshal([]byte(s), &data)
fmt.Printf("Operation: %s", data.name)
}
Output :
Operation:
Program exited.
Try with this one: https://play.golang.com/p/UICf_uNNFdC
I've commented a lot in order to enhance code readability. Be sure to handle error properly and remove debug print.
package main
import (
"encoding/json"
"log"
"strings"
)
type Presence struct {
Presence string
ID string `json:"id"`
Type string `json:"type"`
Deny bool `json:"deny"`
}
type JsonHandler struct {
Name string `json:"name"`
Dat Presence `json:"dat"`
}
func main() {
var (
// Used for unmarshal a given json
packedData []json.RawMessage
err error
// Data that does not have a related json key
name []byte
// Used for extract the raw data that will be unmarshalled into the Presence struct
temp []byte
// Nested json
jsonPresence Presence
handler JsonHandler
)
s := `["Presence",{"id":"905356870666#c.us","type":"unavailable","deny":true}]`
log.Println("Dealing with -> " + s)
// Unmarshall into a raw json message
err = json.Unmarshal([]byte(s), &packedData)
if err != nil {
panic(err)
}
// Extract the presence
log.Println("Presence: ", string(packedData[0]))
// Extract the nested json
log.Println("Packed: ", string(packedData[1]))
// NOTE: 0 refers to the first value of the JSON
name, err = packedData[0].MarshalJSON()
if err != nil {
panic(err)
}
log.Println("Value that does not have a key: " + string(name))
handler.Name = strings.Replace(string(name), "\"", "", -1)
// NOTE: 1 refers to the second value of the JSON, the entire JSON
// Unmarshal the nested Json into byte
temp, err = packedData[1].MarshalJSON()
if err != nil {
panic(err)
}
// Unmarshal the raw byte into the struct
err = json.Unmarshal(temp, &jsonPresence)
if err != nil {
panic(err)
}
log.Println("ID:", jsonPresence.ID)
log.Println("Type:", jsonPresence.Type)
log.Println("Deny:", jsonPresence.Deny)
handler.Dat = jsonPresence
log.Println("Data unmarshalled: ", handler)
}
Go Playground Link: https://play.golang.org/p/qe0jyFVNTH1
Few Problem are present in this:
1. Json Package can't refer the Unexported Structure Elements.So please use Deny instead of deny in the following snippet.This is applicable to all variables declared inside the structure
2. The json fields tag are incorrect. eg.mapstructure:"id" should be json:"id"
3. The json to be parsed contains two distinct elements i.e string "Presence" and nested json object.It can't be parsed as a single element.It is better to declare "Presence" as a key and nested json as the value.
4. The deny variable should be bool rather than string
Wow,solved problem by adding only these codes
Here Go Lang Link : https://play.golang.org/p/doHNWK58Cae
func (n *JsonHandler) UnmarshalJSON(buf []byte) error {
tmp := []interface{}{&n.Name, &n.Dat}
wantLen := len(tmp)
if err := json.Unmarshal(buf, &tmp); err != nil {
return err
}
if g, e := len(tmp), wantLen; g != e {
return fmt.Errorf("wrong number of fields in Notification: %d != %d", g, e)
}
return nil
}
I wanna crawl a site (bbs.archusers.ir) for making a new post or topic notification for users.
I try to write below code for a reading name, last change date, and URL every section and save into struct and save struct into JSON object. but link part in my struct won't get any value and either appear in the console for me, this is my code
package main
import (
"fmt"
"github.com/anaskhan96/soup"
"log"
"os"
"encoding/json"
)
type Message struct {
Name string
Date string
link string
}
type myJSON struct {
Array []Message
}
var input []Message
func main() {
resp, err := soup.Get("https://bbs.archusers.ir")
if err != nil {
os.Exit(1)
}
doc := soup.HTMLParse(resp)
links := doc.Find("div", "id", "brdmain").FindAll("a")
for i := 0; i < len(links); i += 2 {
link := Message{links[i].Text(), links[i+1].Text(), links[i].Attrs()["href"] }
input = append(input, link)
}
if err != nil {
log.Fatal(err)
}
jsondat := &myJSON{input}
encjson, _ := json.Marshal(jsondat)
fmt.Println(string(encjson))
}
which part I did wrong?
There is a problem in your Message struct
it must name 'link' with capital k ---< Link
type Message struct {
Name string
Date string
Link string
}
and output will be correct
{"Name":"مانجارو Manjaro","Date":"2018-10-18 10:55:09","Link":"viewforum.php?id=22"}
We get some JSON input, unmarshal, perform some work, then marshal and ship off somewhere else. The JSON we get may have a field named "user". When we marshal back to JSON we need to have that field "user" changed to "username". We can do this by creating a new struct with all the same fields, but different JSON tags, but that seemed a bit cumbersome. I thought a custom marshaller would work here, but I'm a bit stuck. Consider the following code.
package main
import (
"encoding/json"
"fmt"
)
type StructA struct {
Username string `json:"user"`
Process string `json:"process"`
}
func main() {
var test1 StructA
err := json.Unmarshal([]byte(`{"user": "user123", "process": "something"}`), &test1)
if err != nil {
fmt.Println(err)
}
// do some work with test1
jsonByte, err := json.Marshal(&test1)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(jsonByte))
}
func (u *StructA) MarshalJSON() ([]byte, error) {
type Alias StructA
return json.Marshal(&struct {
Username string `json:"username"`
*Alias
}{
Username: u.Username,
Alias: (*Alias)(u),
})
}
https://play.golang.org/p/_w0rlQrcgrW
Ideally this would allow me to change the JSON tag on that field from "user" to "username". However, I get both "username" and "user".
{"username":"user123","user":"user123","process":"something"}
I certainly could create an entirely new struct that mirrors StructA with the tags I want, but I don't have to have to copy every single field and worry about keeping those two structs in sync. It's not the end of the world, but it doesn't seem like a good approach.
To be clear, the end result I'm looking for is the following:
{"username":"user123","process":"something"}
I'm sure I'm missing something trivial here, but it's been a long week and any assistance would be appreciated. Thanks!
One option could be to have one struct with the non-changing values and than 2 alternative structs which both include that struct and have only the changing values. You then use one for unmarshaling and the second one for marshaling.
type StructA struct {
Process string `json:"process"`
...
}
type WithUser struct {
StructA
Username `json:"user"`
}
type WithUsername struct {
StructA
Username `json:"username"`
}
This would require multiple structs but no duplication in each one and can be quite flexible in what you include, instead of hard coding what you want to change into a custom marshal function.
use reflect to create struct and change it's tag
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type StructA struct {
Username string `json:"user"`
Process string `json:"process"`
}
func main() {
var test1 StructA
err := json.Unmarshal([]byte(`{"user": "user123", "process": "something"}`), &test1)
if err != nil {
fmt.Println(err)
}
// do some work with test1
jsonByte, err := json.Marshal(&test1)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(jsonByte))
}
func (u *StructA) MarshalJSON() ([]byte, error) {
// get old struct fields
uType := reflect.TypeOf(u).Elem()
userNameField, _ := uType.FieldByName("Username")
// set username field tag
userNameField.Tag = `json:"username"`
processField, _ := uType.FieldByName("Process")
newType := reflect.StructOf([]reflect.StructField{userNameField, processField})
// set new value field
oldValue := reflect.ValueOf(u).Elem()
newtValue := reflect.New(newType).Elem()
for i := 0; i < oldValue.NumField(); i++ {
newtValue.Field(i).Set(oldValue.Field(i))
}
return json.Marshal(newtValue.Interface())
}
I'm trying to do an API request to get some information from steams public API (this is mainly for learning Go and just learning how to deal with Json / API requests) I have gotten this code so far:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
)
type SteamAPI struct {
APIKey string
}
type GetAppNews struct {
AppNews struct {
AppId int `json:"appid"`
NewsItems []struct {
Gid int `json:"gid"`
Title string `json:"title"`
Url string `json:"url"`
IsExternalUrl bool `json:"is_external_url"`
Author string `json:"author"`
Contents string `json:"contents"`
Feedlabel string `json:"feedlabel"`
Date int `json:"date"`
} `json:"newsitems"`
} `json:"appnews"`
}
type JsonResponse map[string]GetAppNews
func (s SteamAPI) GetNewsForApp(appid, count, maxlength int) error {
sAppid := strconv.Itoa(appid)
sCount := strconv.Itoa(count)
sMaxlength := strconv.Itoa(maxlength)
resp, err := http.Get("http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=" + sAppid + "&count=" + sCount + "&maxlength=" + sMaxlength + "&format=json")
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
var jsonReturn JsonResponse
json.Unmarshal(body, &jsonReturn)
fmt.Println(jsonReturn)
return nil
}
func main() {
Tester := SteamAPI{""}
Tester.GetNewsForApp(440, 3, 300)
}
Things seem to work, alright, I guess but its not formatting it the way I would expect it to Unmarshal. It prints out like this:
map[appnews:{{0 []}}]
You can click here to see exactly what the format of the JSON response looks like, if anybody could tell me what I have done wrong with my struct, in the end I expect to be able to go something like:
fmt.Println(blah["appnews"]["appid"]) and it would return 440.
Thats all I really got to go off of, if you need anymore specific information let me know! Thanks for the help!
The data fits the struct just fine, no need for map[string]GetAppNews.
type JsonResponse map[string]GetAppNews should just be GetAppNews.
playground
My websocket server will receive and unmarshal JSON data. This data will always be wrapped in an object with key/value pairs. The key-string will act as value identifier, telling the Go server what kind of value it is. By knowing what type of value, I can then proceed to JSON unmarshal the value into the correct type of struct.
Each json-object might contain multiple key/value pairs.
Example JSON:
{
"sendMsg":{"user":"ANisus","msg":"Trying to send a message"},
"say":"Hello"
}
Is there any easy way using the "encoding/json" package to do this?
package main
import (
"encoding/json"
"fmt"
)
// the struct for the value of a "sendMsg"-command
type sendMsg struct {
user string
msg string
}
// The type for the value of a "say"-command
type say string
func main(){
data := []byte(`{"sendMsg":{"user":"ANisus","msg":"Trying to send a message"},"say":"Hello"}`)
// This won't work because json.MapObject([]byte) doesn't exist
objmap, err := json.MapObject(data)
// This is what I wish the objmap to contain
//var objmap = map[string][]byte {
// "sendMsg": []byte(`{"user":"ANisus","msg":"Trying to send a message"}`),
// "say": []byte(`"hello"`),
//}
fmt.Printf("%v", objmap)
}
Thanks for any kind of suggestion/help!
This can be accomplished by Unmarshaling into a map[string]json.RawMessage.
var objmap map[string]json.RawMessage
err := json.Unmarshal(data, &objmap)
To further parse sendMsg, you could then do something like:
var s sendMsg
err = json.Unmarshal(objmap["sendMsg"], &s)
For say, you can do the same thing and unmarshal into a string:
var str string
err = json.Unmarshal(objmap["say"], &str)
EDIT: Keep in mind you will also need to export the variables in your sendMsg struct to unmarshal correctly. So your struct definition would be:
type sendMsg struct {
User string
Msg string
}
Example: https://play.golang.org/p/OrIjvqIsi4-
Here is an elegant way to do similar thing. But why do partly JSON unmarshal? That doesn't make sense.
Create your structs for the Chat.
Decode json to the Struct.
Now you can access everything in Struct/Object easily.
Look below at the working code. Copy and paste it.
import (
"bytes"
"encoding/json" // Encoding and Decoding Package
"fmt"
)
var messeging = `{
"say":"Hello",
"sendMsg":{
"user":"ANisus",
"msg":"Trying to send a message"
}
}`
type SendMsg struct {
User string `json:"user"`
Msg string `json:"msg"`
}
type Chat struct {
Say string `json:"say"`
SendMsg *SendMsg `json:"sendMsg"`
}
func main() {
/** Clean way to solve Json Decoding in Go */
/** Excellent solution */
var chat Chat
r := bytes.NewReader([]byte(messeging))
chatErr := json.NewDecoder(r).Decode(&chat)
errHandler(chatErr)
fmt.Println(chat.Say)
fmt.Println(chat.SendMsg.User)
fmt.Println(chat.SendMsg.Msg)
}
func errHandler(err error) {
if err != nil {
fmt.Println(err)
return
}
}
Go playground
Further to Stephen Weinberg's answer, I have since implemented a handy tool called iojson, which helps to populate data to an existing object easily as well as encoding the existing object to a JSON string. A iojson middleware is also provided to work with other middlewares. More examples can be found at https://github.com/junhsieh/iojson
Example:
func main() {
jsonStr := `{"Status":true,"ErrArr":[],"ObjArr":[{"Name":"My luxury car","ItemArr":[{"Name":"Bag"},{"Name":"Pen"}]}],"ObjMap":{}}`
car := NewCar()
i := iojson.NewIOJSON()
if err := i.Decode(strings.NewReader(jsonStr)); err != nil {
fmt.Printf("err: %s\n", err.Error())
}
// populating data to a live car object.
if v, err := i.GetObjFromArr(0, car); err != nil {
fmt.Printf("err: %s\n", err.Error())
} else {
fmt.Printf("car (original): %s\n", car.GetName())
fmt.Printf("car (returned): %s\n", v.(*Car).GetName())
for k, item := range car.ItemArr {
fmt.Printf("ItemArr[%d] of car (original): %s\n", k, item.GetName())
}
for k, item := range v.(*Car).ItemArr {
fmt.Printf("ItemArr[%d] of car (returned): %s\n", k, item.GetName())
}
}
}
Sample output:
car (original): My luxury car
car (returned): My luxury car
ItemArr[0] of car (original): Bag
ItemArr[1] of car (original): Pen
ItemArr[0] of car (returned): Bag
ItemArr[1] of car (returned): Pen