Go return struct as JSON in HTTP request - go

I've defined the following struct in Go:
type repoStars struct {
name string
owner string
stars int
}
And I've created an array repoItems := []repoStars{} which has multiple items of the struct above.
This is how repoItems looks like:
I'm trying to return those items as a JSON response:
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(repoItems)
And it seems empty
What am I doing wrong here?

If the struct fields start with a lower case letter it means unexported. All unexported fields won't be serialised by the encoder.
Change it to capital first letter.
type repoStars struct {
Name string
Owner string
Stars int
}

Related

How to access the fields of this struct in Golang

I'm new to Golang and I need to know how to access the value from a struct of the format:
type CurrentSkuList struct {
SubscriptionNumber string `json:"subscriptionNumber`
Quantity int `json:"quantity"`
SubscriptionProducts []struct {
ID int `json:"id"`
ActiveStartDate int `json:"activeStartDate"`
ActiveEndDate int `json:"activeEndDate"`
Status string `json:"status"`
Sku string `json:"sku"`
ChildIDs []int `json:"childrenIds"`
} `json:"subscriptionProducts"`
}
For example, if I have a variable currentSkus of type CurrentSkuList and I need to access only Sku and Status values, is there a way to do something like:
currentSkus.SubscriptionProducts.Sku?
EDIT! When I try to access currentSkus.Quantity I get a compiler error undefined (type []util.CurrentSkuList has no field or method Quantity).
Yeah, there is a way. You can access by the . syntax you proposed. In this case, CurrentSkuList is returning an slice of SubscriptionProduct, you know that because of the [] struct part. Then you would have to access to the data this way:
currentSkus.SubscriptionProducts[index].Sku

Dynamically Create Structs in Golang

So I am working with an external API, whose responses I wanted to parse. The incoming responses are of a fixed format i.e.
type APIResponse struct {
Items []interface{} `json:"items"`
QuotaMax int `json:"quota_max"`
QuotaRemaining int `json:"quota_remaining"`
}
So for each response I am parsing the items. Now the items can be of diff types as per the request. It can be a slice of sites, articles, etc. Which have their individual models. like:
type ArticleInfo struct {
ArticleId uint64 `json:"article_id"`
ArticleType string `json:"article_type"`
Link string `json:"link"`
Title string `json:"title"`
}
type SiteInfo struct {
Name string `json:"name"`
Slug string `json:"slug"`
SiteURL string `json:"site_url"`
}
Is there any way, when parsing the input define the type of Items in APIResponse. I don't want to create separate types for individual responses.
Basically want to Unmarshall any incoming response into the APIResponse struct.
Change type of the Items field to interface{}:
type APIResponse struct {
Items interface{} `json:"items"`
...
}
Set the response Items field to pointer of the desired type. Unmarshal to the response:
var articles []ArticleInfo
response := APIResponse{Items: &articles}
err := json.Unmarshal(data, &response)
Access the articles using variable articles.
Run an example on the playground.

Better way of decoding json values

Assume a JSON object with the general format
"accounts": [
{
"id": "<ACCOUNT>",
"tags": []
}
]
}
I can create a struct with corresponding json tags to decode it like so
type AccountProperties struct {
ID AccountID `json:"id"`
MT4AccountID int `json:"mt4AccountID,omitempty"`
Tags []string `json:"tags"`
}
type Accounts struct {
Accounts []AccountProperties `json:"accounts"`
}
But the last struct with just one element seems incorrect to me. Is there a way I could simply say type Accounts []AccountProperties `json:"accounts"` instead of creating an entire new struct just to decode this object?
You need somewhere to store the json string accounts. Using a:
var m map[string][]AccountProperties
suffices, though of course you then need to know to use the string literal accounts to access the (single) map entry thus created:
type AccountProperties struct {
ID string `json:"id"`
MT4AccountID int `json:"mt4AccountID,omitempty"`
Tags []string `json:"tags"`
}
func main() {
var m map[string][]AccountProperties
err := json.Unmarshal([]byte(data), &m)
fmt.Println(err, m["accounts"])
}
See complete Go Playground example (I had to change the type of ID to string and fix the missing { in the json).
As Dave C points out in comments, this is no shorter than just using an anonymous struct type:
var a struct{ Accounts []AccountProperties }
in terms of the Unmarshall call (and when done this way it's more convenient to use). Should you want to use an anonymous struct like this in a json.Marshall call, you'll need to tag its single element to get a lowercase encoding: without a tag it will be called "Accounts" rather than "accounts".
(I don't claim the map method to be better, just an alternative.)

Golang Decode a BSON with special character Keys to a struct

I have a Golang struct called Person where all the properties have to be exported:
type Person struct {
Id string
Name string
}
Now I need to encode my MongoDB BSON response to this Person struct. The BSON looks like:
{
"_id": "ajshJSH78N",
"Name": "Athavan Kanapuli"
}
The Golang code to encode the BSON is:
mongoRecord := Person{}
c := response.session.DB("mydb").C("users")
err := c.Find(bson.M{"username": Credentials.Username, "password": Credentials.Password}).One(&mongoRecord)
The Problem:
_id is not getting encoded into Id
If I change the Person property into _Id, then it won't be exported.
How can I solve this problem?
Define your struct with json tag-
type Person struct {
Id string `json:"_id"`
Name string // this field match with json, so mapping not need
}
I tried to put a json tag like ,
type Person struct {
Id string `json:"_id"`
Name string // this field match with json, so mapping not need
}
But still it didn't work. Because the Mongodb returns '_id' which is of type bson.ObjectId . Hence changing the Struct tag to bson:"_id" and the type of the Person struct has been changed from string to bson.ObjectId. The changes done are as follows ,
type Person struct {
Id bson.ObjectId `bson:"_id"`
Name string
UserName string
IsAdmin bool
IsApprover bool
}
And It works!

how tags of struct fields are used?

I do not understand how field tags in struct are used and when. Per https://golang.org/ref/spec#Struct_types:
[tag] becomes an attribute for all the fields in the corresponding field declaration
what does this mean?
[tag] becomes an attribute for all the fields in the corresponding field declaration
In addition to the links above ("What are the use(s) for tags in Go?", "go lang, struct: what is the third parameter") this thread provides an example which does not come from the standard packages:
Suppose I have the following code (see below). I use a type switch the check the type of the argument in WhichOne().
How do I access the tag ("blah" in both cases)?
I'm I forced the use the reflection package, or can this also be done in "pure" Go?
type PersonAge struct {
name string "blah"
age int
}
type PersonShoe struct {
name string "blah"
shoesize int
}
func WhichOne(x interface{}) {
...
}
After reading that (again), looking in json/encode.go and some trial and error, I have found a solution.
To print out "blah" of the following structure:
type PersonAge struct {
name string "blah"
age int
}
You'll need:
func WhichOne(i interface{}) {
switch t := reflect.NewValue(i).(type) {
case *reflect.PtrValue:
x := t.Elem().Type().(*reflect.StructType).Field(0).Tag
println(x)
}
}
Here: Field(0).Tag illustrates the "becomes an attribute for all the fields in the corresponding field declaration".

Resources