I have built a Golang REST API. Other HTTP verbs works well except the GET
that fetches everything from the database.
I have a nested struct for the model as shown below:
type Config struct {
ID int `json:"id"`
Name string `json:"name,omitempty"`
Data *Data `json:"data,omitempty"`
}
type Data struct {
Host string `json:"host,omitempty"`
Database string `json:"database,omitempty"`
Password string `json:"password,omitempty"`
Username string `json:"username,omitempty"`
Engine string `json:"engine,omitempty"`
}
I do JSON unmarshal against the Data. See the code below:
model.go
func List(db *sql.DB, start, count int) ([]Config, error) {
var dt string
var c Config
rows, err := db.Query(
"SELECT * FROM configs LIMIT $1 OFFSET $2",
count, start)
if err != nil {
return nil, err
}
defer rows.Close()
configs := []Config{}
for rows.Next() {
//var c Config
if err := rows.Scan(&c.ID, &c.Name, &dt); err != nil {
return nil, err
}
json.Unmarshal([]byte(dt), &c.Data)
// for _, p := range c.Data {
// configs = append(configs, c)
// }
configs = append(configs, c)
}
return configs, nil
}
controller.go
func (a *App) getConfigs(w http.ResponseWriter, r *http.Request) {
count, _ := strconv.Atoi(r.FormValue("count"))
start, _ := strconv.Atoi(r.FormValue("start"))
if count > 10 || count < 1 {
count = 10
}
if start < 0 {
start = 0
}
configs, err := List(a.DB, start, count)
fmt.Print(configs)
if err != nil {
fatalError(w, http.StatusInternalServerError, err.Error())
return
}
jsonResponse(w, http.StatusOK, configs)
}
When I hit the get endpoint, I get the following:
[
{
"id": 2,
"name": "test2",
"data": {
"host": "newhosty",
"database": "locau",
"password": "poy",
"username": "psq",
"engine": "dgnewy"
}
},
{
"id": 3,
"name": "test3",
"data": {
"host": "newhosty",
"database": "locau",
"password": "poy",
"username": "psq",
"engine": "dgnewy"
}
},
{
"id": 4,
"name": "test39",
"data": {
"host": "newhosty",
"database": "locau",
"password": "poy",
"username": "psq",
"engine": "dgnewy"
}
}
]
As you can see, the data
part of the json is duplicated for all the id
. Only name
and id
work as expected. I expected each data to be different as it is in the db. Looks like it only picks the last row for the data part.
Anything I'm doing wrong?
I fixed this by replacing Data *Data
with Data Data
. The problem was When json.Unmarshal
fills c.Data
it sees that there is already a struct in it and overwrites it.