In my golang code, I use net/http and gorilla mux.
In the function below, when I encode the nested structure variable, the http response shows blank "{}". However, if I encode only one of the non-nested struct's they show up ok.
Can you please help how I can send the nested-structure in http-response? Thank you
func getNestedStruct(w http.ResponseWriter, r *http.Request) {
type User1 struct {
ID int `json:"Id1"`
Email string `json:"Email1"`
Password string `json:"Password1"`
}
type User2 struct {
ID int `json:"Id2"`
Email string `json:"Email2"`
}
type Users struct {
MyUser1 User1 `json:"User1"`
MyUser2 User2 `json:"User1"`
}
var myUser1 User1
var myUser2 User2
var myUsers Users
myUser1.ID = 1
myUser1.Email = "user1#email.com"
myUser1.Password = "user1"
myUser2.ID = 2
myUser2.Email = "user2#email.com"
myUsers.MyUser1 = myUser1
myUsers.MyUser2 = myUser2
// these print without issues
log.Printf("getNestedStruct: Struct User1: ", myUser1)
log.Printf("getNestedStruct: Struct User2: ", myUser2)
log.Printf("getNestedStruct: Nested Struct Users: ", myUsers)
// This does not work --> shows {} in http response
json.NewEncoder(w).Encode(myUsers)
// This works:
//json.NewEncoder(w).Encode(myUser1)
}
MyUser1 & MyUser2 both have the same JSON key. Giving different keys should work
type Users struct {
MyUser1 User1 `json:"User1"`
MyUser2 User2 `json:"User2"`
}
Related
I have config.yml file:
vcenter:
connection: https
hostname: vcenter.mydomain.lan
username: readonlyauto#vsphere.local
password: mypasspord
port: 443
EsxiExcludeDatastores:
- datastore1
- datastore2
EsxiExcludeDatastores2:
datastores:
- datastore1
- datastore2
I'm trying to parse it with "gopkg.in/yaml.v2"
I created struct:
type FileConfig struct {
Vcenter struct {
ConnectionType string `yaml:"connection"`
Hostname string `yaml:"hostname"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Port int `yaml:"port"`
} `yaml:"vcenter"`
EsxiExcludeDatastores struct {
Datastores []string `yaml:"EsxiExcludeDatastores"`
}
EsxiExcludeDatastores2 struct {
Datastores []string `yaml:"datastores"`
} `yaml:"EsxiExcludeDatastores2"`
}
var AppConfig FileConfig
After parsing, I print results:
fmt.Println("Num of EsxiExcludeDatastores.Datastores = ", len(AppConfig.EsxiExcludeDatastores.Datastores))
fmt.Println("Num of EsxiExcludeDatastores2.Datastores = ", len(AppConfig.EsxiExcludeDatastores2.Datastores))
Num of EsxiExcludeDatastores.Datastores = 0
Num of EsxiExcludeDatastores2.Datastores = 2
Can you help me, where I did mistake in EsxiExcludeDatastores struct? As you see, everything is fine with EsxiExcludeDatastores2, but EsxiExcludeDatastores is empty.
I tried to do this in different ways, but with no result ...
You're almost there.
To "promote" yaml struct tag(s) to the "parent" field, add:
EsxiExcludeDatastores struct {
Datastores []string `yaml:"EsxiExcludeDatastores"`
} `yaml:",inline"` // <- this
https://play.golang.org/p/S7QxGaspTyN
From the yaml.v2 docs, a struct tag that uses the inline flag does the following:
Inline the field, which must be a struct or a map, causing all of its
fields or keys to be processed as if they were part of the outer
struct. For maps, keys must not conflict with the yaml keys of other
struct fields.
type listParams struct {
Status int `form:"status"`
Keyword string `form:"keyword"`
ShowType int `form:"show_type"`
}
func List(c *gin.Context) {
var ReqData listParams
_ = c.ShouldBind(&ReqData)
// I fetch this by PostForm() to check it empy if it equal to empty string
if stat := c.PostForm("status"); stat == "" {
ReqData.Status = -99
}
// .......
}
In this code, How can I know that was front-end post the status or not?
Because of the default value of go, if I check the reqData.Status == 0, it will always return true if the front-end didn't post it, but In my case, 0 is a meaningful value, So I can't check it by equal to 0.
So am I have the others way to check it?
PS: I tried and found out that gorm will not update the field in struct if I don't assign:
var d &User{} // User is a definition of user table
d.ID = 1
d.Name = "Joy"
// d.Status = 1 // It has this field, but I dont assign it
db.Model(&User{}).updates(&d)
Finally, status won't update to 0(In my understanding, d.Status should be 0)
Use a pointer type to circumvent the 0 default value:
type listParams struct {
Status &int `form:"status"`
Keyword string `form:"keyword"`
ShowType int `form:"show_type"`
}
The check if d.Status is nil, otherwise get the associated value
I think this constraint raises the need for having a sole public way to construct User.
type user struct { Status int Keyword string ShowTypeint}
func NewUser() (*user) { return &user{Status: -1} }
That way you ensure that user struct is only constructed through NewUser having Status default value Status always equal to -1.
type Old struct {
UserID int `json:"user_ID"`
Data struct {
Address string `json:"address"`
} `json:"old_data"`
}
type New struct {
UserID int `json:"userId"`
Data struct {
Address string `json:"address"`
} `json:"new_data"`
}
func (old Old) ToNew() New {
return New{
UserID: old.UserID,
Data: { // from here it says missing expression
Address: old.Data.Address,
},
}
}
What is "missing expression" error when using structs?
I am transforming old object to a new one. I minified them just to get straight to the point but the transformation is much more complex. The UserID field for example works great. But when I use struct (which intended to be a JSON object in the end) the Goland IDE screams "missing expression" and the compiler says "missing type in composite literal" on this line. What I am doing wrong? Maybe should I use something else instead of struct? Please help.
Data is an anonymous struct, so you need to write it like this:
type New struct {
UserID int `json:"userId"`
Data struct {
Address string `json:"address"`
} `json:"new_data"`
}
func (old Old) ToNew() New {
return New{
UserID: old.UserID,
Data: struct {
Address string `json:"address"`
}{
Address: old.Data.Address,
},
}
}
(playground link)
I think it'd be cleanest to create a named Address struct.
You're defining Data as an inline struct. When assigning values to it, you must first put the inline declaration:
func (old Old) ToNew() New {
return New{
UserID: old.UserID,
Data: struct {
Address string `json:"address"`
}{
Address: old.Data.Address,
},
}
}
Hence it is generally better to define a separate type for Data, just like User.
Now I'm working on GO RPC, I'm using gRPC+Protobuf. And I follow openconfig's data struct, so I could NOT redesign.
I need to fill protobuf struct and Marshal it and send it out, and then client will Unmarshal it and read datas.
My protobuf file(xxx.pb.go) is complicated, for example, just like this:
type ObjBase struct {
a *ObjChildAlice,
b *ObjChildBob,
... // there are many variables like ObjChildCheer, ObjChildDog ...
}
type ObjChildAlice struct {
child *ObjChildChild,
}
type ObjChildBob struct {
child *ObjChildChild,
}
// there are many types like ObjChildCheer, ObjChildDog ...
type ObjChildChild {
int i,
}
In server side, I need to fill ObjBase and send it out, this is my task:
// Code 1
func () {
init ob with ObjBase
if DataBase has Alice {
fill ob.a with ObjChildAlice
}
if DataBase has Bob {
fill ob.a with ObjChildBob
}
// there are many if..else.. DataBase has Cheer...
return ob
}
So I code like this first:
// Code 2
func () {
ob := new(ObjBase)
oba := new(ObjChildAlice)
obb := new(ObjChildBob)
if DataBase has Alice {
ob.a = oba
}
if DataBase has Bob {
ob.b = obb
}
...
return ob
}
But this code could NOT work, as I check member of ob.a and ob.b are all zero.
So I change like this:
// Code 3
func () {
if DataBase has Alice && DataBase has Bob {
ob := &ObjBase{
a: &ObjChildAlice{},
b: &ObjChildBob{},
}
} else if DataBase has Alice && NOT DataBase has Bob {
ob := &ObjBase{
a: &ObjChildAlice{},
}
} else if ...
return ob
}
This works. But in database, there are kinds of variables like Alice, Bob, Cheer, Dog ... It's impossible to use if..else.. to do this work.
So I have questions:
Why ob'member in Code2 is zero?
is there any way to set Go struct's member object dynamically?
Please take a look at this doc which talks the Go generated code for protobufs. https://developers.google.com/protocol-buffers/docs/reference/go-generated
You should be able to set a protobuf message field in the generated code by directly accessing the corresponding member field (which is exported).
Is there a good way to embed initialized struct variables in another struct?
Consider the following situation:
type Account struct {
AdminUser, AdminPass string
}
const (
acc1: "account_user",
pass: "111222"
)
var AccountDef = Account {
AdminUser: "acc1",
AdminPass: "pass1"
}
type Login struct {
Acc *AccountDef
Username, Password, Token string
}
var LoginDef = Login {
Token: "adaasdasddas1123"
}
I want to reuse AccountDef in Login, then I want to instantiate LoginDef in another function then use it for rendering templates like LoginDef.Acc.AdminUser
Is this possible to do?
If you want a Login to contain the fields from an Account, you can embed them like so:
http://play.golang.org/p/4DXnIsILd6
type Account struct {
AdminUser string
AdminPass string
}
type Login struct {
*Account
Username, Password, Token string
}
func main() {
acct := &Account{
AdminUser: "username",
AdminPass: "pass",
}
login := Login{Account: acct}
fmt.Println("login.AdminUser:", login.AdminUser)
fmt.Println("login.AdminPass:", login.AdminPass)
}