Unmarshal a dynamic json - json

I have a bunch of JSON files that I need to Unmarshal. They have basically the same format, but different "length"
one example
https://pastebin.com/htt6k658
another example
https://pastebin.com/NR1Z08f4
I have tried several methods, like building structs like
type TagType struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
tags []Tag `json:"tags"`
}
type Tag struct {
ID int `json:"users"`
Name string `json:"name"`
Slug string `json:"slug"`
}
also with an interface, like
json.Unmarshal([]byte(empJson), &result)
but none of these methods worked.

The JSON input is an array, so this should work:
var result []TagType
json.Unmarshal(data,&result)

You can use a online tool like https://transform.tools/json-to-go for generating the Go struct:
type AutoGenerated []struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Tags []struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
} `json:"tags"`
}

Related

Receiving unknown response body

I am implementing the Authorize.net credit card API. The API always gives me a 200 response code regardless if the transaction is successful or it is declined. But it gives the one response body for successful transaction and a different one for declined transaction.
type AuthorizeApprovedResponse struct {
TransactionResponse struct {
ResponseCode string `json:"responseCode"`
AuthCode string `json:"authCode"`
AvsResultCode string `json:"avsResultCode"`
CvvResultCode string `json:"cvvResultCode"`
CavvResultCode string `json:"cavvResultCode"`
TransID string `json:"transId"`
RefTransID string `json:"refTransID"`
TransHash string `json:"transHash"`
TestRequest string `json:"testRequest"`
AccountNumber string `json:"accountNumber"`
AccountType string `json:"accountType"`
Messages []struct {
Code string `json:"code"`
Description string `json:"description"`
} `json:"messages"`
UserFields []struct {
Name string `json:"name"`
Value string `json:"value"`
} `json:"userFields"`
TransHashSha2 string `json:"transHashSha2"`
SupplementalDataQualificationIndicator int `json:"SupplementalDataQualificationIndicator"`
NetworkTransID string `json:"networkTransId"`
} `json:"transactionResponse"`
RefID string `json:"refId"`
Messages struct {
ResultCode string `json:"resultCode"`
Message []struct {
Code string `json:"code"`
Text string `json:"text"`
} `json:"message"`
} `json:"messages"`
}
type AuthorizeDeclinedResponse struct {
TransactionResponse struct {
ResponseCode string `json:"responseCode"`
AuthCode string `json:"authCode"`
AvsResultCode string `json:"avsResultCode"`
CvvResultCode string `json:"cvvResultCode"`
CavvResultCode string `json:"cavvResultCode"`
TransID string `json:"transId"`
RefTransID string `json:"refTransID"`
TransHash string `json:"transHash"`
TestRequest string `json:"testRequest"`
AccountNumber string `json:"accountNumber"`
AccountType string `json:"accountType"`
Errors []struct {
ErrorCode string `json:"errorCode"`
ErrorText string `json:"errorText"`
} `json:"errors"`
UserFields []struct {
Name string `json:"name"`
Value string `json:"value"`
} `json:"userFields"`
TransHashSha2 string `json:"transHashSha2"`
SupplementalDataQualificationIndicator int `json:"SupplementalDataQualificationIndicator"`
NetworkTransID string `json:"networkTransId"`
} `json:"transactionResponse"`
RefID string `json:"refId"`
Messages struct {
ResultCode string `json:"resultCode"`
Message []struct {
Code string `json:"code"`
Text string `json:"text"`
} `json:"message"`
} `json:"messages"`
}
Here is my problem, which struct to use. I was thinking of trying an interface{} and then try to cast it to a struct?
err := json.Unmarshal(b, &whichStructToUse)
if err != nil {
panic(err.Error())
}
Any advice on how to Unmarshal the response when I don't know which struct to use?
The API always gives me a 200 response code regardless if the transaction is successful or it is declined.
I feel your pain.
There's only one difference between the two responses, success has Messages and failure has Errors. Combine them.
type CommonResponse struct {
TransactionResponse struct {
ResponseCode string `json:"responseCode"`
AuthCode string `json:"authCode"`
AvsResultCode string `json:"avsResultCode"`
CvvResultCode string `json:"cvvResultCode"`
CavvResultCode string `json:"cavvResultCode"`
TransID string `json:"transId"`
RefTransID string `json:"refTransID"`
TransHash string `json:"transHash"`
TestRequest string `json:"testRequest"`
AccountNumber string `json:"accountNumber"`
AccountType string `json:"accountType"`
Messages []struct {
Code string `json:"code"`
Description string `json:"description"`
} `json:"messages"`
Errors []struct {
ErrorCode string `json:"errorCode"`
ErrorText string `json:"errorText"`
} `json:"errors"`
UserFields []struct {
Name string `json:"name"`
Value string `json:"value"`
} `json:"userFields"`
TransHashSha2 string `json:"transHashSha2"`
SupplementalDataQualificationIndicator int `json:"SupplementalDataQualificationIndicator"`
NetworkTransID string `json:"networkTransId"`
} `json:"transactionResponse"`
RefID string `json:"refId"`
Messages struct {
ResultCode string `json:"resultCode"`
Message []struct {
Code string `json:"code"`
Text string `json:"text"`
} `json:"message"`
} `json:"messages"`
}
Then use that to unmarshall and check for Errors.
var response CommonResponse;
json.Unmarshal([]byte(jsonString), &response)
if len(response.Error) == 0 {
fmt.Println("Success!")
} else {
fmt.Println("Error!")
}
For the more general case, you can unmarshall to a map[string]interface{}.
var result map[string]interface{}
json.Unmarshal([]byte(jsonString), &result)
Demonstration.

show json array inside of a json object using gorm

I'm trying to use gorm for my queries. I have a model called users just like this:
type Users struct {
gorm.Model
ID uint `gorm:"autoIncrement;unique" json:"id"`
PhoneNumber string `gorm:"primaryKey" json:"phone_number"`
Name string `gorm:"default:dear user" json:"name"`
Rank uint `json:"rank"`
Score uint `json:"score"`
Image string `json:"image"`
Email string `json:"email"`
Address string `json:"address"`
Birthday string `json:"birthday"`
Biography string `json:"biography"`
}
and another model which represents the courses that the user has purchased.
type UserCourse struct {
CourseID uint `gorm:"primaryKey" json:"course_id"`
UserPhoneNumber string `gorm:"primaryKey" json:"user_phone_number"`
Progress uint `json:"progress"`
CreatedAt time.Time
UpdatedAt time.Time
}
now I am looking for a way to return top 100 users based on their score with the courses they have purchased. in the other word, the below JSON object is desirable:
{
"users":[
{
"id":1,
"phoneNumber":"99999999",
"name":"test",
"rank":1,
"score":123456789,
"image":"http://...",
"email":"test#test.com",
"address":"test",
"birthday":"2021-01-01",
"biography":"test here",
"courses": [
{
"course_id":1,
"user_phone_number":"99999999",
"progress": 53,
"created_at": "2021-01-01",
"updated_at": "2021-01-01",
} ,
{
"course_id":2,
"user_phone_number":"99999999",
"progress":100,
"created_at":"2021-02-01",
"updated_at":"2021-03-01",
}
]
}
]
}
I know I have to use the below query to get top 100 users:
database.myDatabase.Order("rank asc").Limit(100).Find(users)
but unfortunately, I have no idea how to write the gorm suitable for the mentioned output.
If you extend your Users model as such:
type Users struct {
gorm.Model
ID uint `gorm:"autoIncrement;unique" json:"id"`
PhoneNumber string `gorm:"primaryKey" json:"phone_number"`
Name string `gorm:"default:dear user" json:"name"`
Rank uint `json:"rank"`
Score uint `json:"score"`
Image string `json:"image"`
Email string `json:"email"`
Address string `json:"address"`
Birthday string `json:"birthday"`
Biography string `json:"biography"`
Courses []*UserCourse `gorm:"foreignKey:UserPhoneNumber;references:PhoneNumber" json:"courses"`
}
you can then preload the courses into the user struct by using:
database.myDatabase.Preload("Courses").Order("rank asc").Limit(100).Find(users)

How do I access certain values in this struct [duplicate]

This question already has answers here:
How to get JSON value based on other JSON values
(2 answers)
Closed 2 years ago.
I am logging something in Go. Here is the value and below that is the result when I log reflect.TypeOf(attributes.Pdp.SellableUnits[i].Attributes):
[{22555278 val 03.5}]
[{22554867 val 04.0}]
[{22555002 val 04.5}]
[{22555279 val 05.0}]
[{22555280 val 05.5}]
[{22555144 val 06.0}]
[{22555145 val 06.5}]
[{22555146 val 07.0}]
// TypeOf
[1]struct { ID string "json:\"id\""; Type string "json:\"type\""; Value string "json:\"value\"" }
[1]struct { ID string "json:\"id\""; Type string "json:\"type\""; Value string "json:\"value\"" }
[1]struct { ID string "json:\"id\""; Type string "json:\"type\""; Value string "json:\"value\"" }
[1]struct { ID string "json:\"id\""; Type string "json:\"type\""; Value string "json:\"value\"" }
[1]struct { ID string "json:\"id\""; Type string "json:\"type\""; Value string "json:\"value\"" }
[1]struct { ID string "json:\"id\""; Type string "json:\"type\""; Value string "json:\"value\"" }
[1]struct { ID string "json:\"id\""; Type string "json:\"type\""; Value string "json:\"value\"" }
[1]struct { ID string "json:\"id\""; Type string "json:\"type\""; Value string "json:\"value\"" }
I want to be able to log the ID string only, in this case being the string of many numbers at the top of the code block (22555278, 22554867, 22555002, etc...)
Here is my code to log all of this
// Struct
type sizeJ struct {
Pdp struct {
Units []struct {
Attributes [1]struct {
ID string `json:"id"`
Type string `json:"type"`
Value string `json:"value"`
} `json:"attributes"`
} `json:"Units"`
} `json:"pdp"`
}
// ...
body, _ := ioutil.ReadAll(resp.Body)
xml := strings.NewReader(string(body))
j, _ := xj.Convert(xml)
if err != nil {
log.Fatal(err)
}
var attributes sizeJ
json.Unmarshal([]byte(j.String()), &attributes)
for i := 0; i < len(attributes.Pdp.Units); i++ {
fmt.Println(reflect.TypeOf(attributes.Pdp.Units[i].Attributes))
}
Your type is declared as:
type sizeJ struct {
Pdp struct {
Units []struct {
Attributes [1]struct {
ID string `json:"id"`
Type string `json:"type"`
Value string `json:"value"`
} `json:"attributes"`
} `json:"Units"`
} `json:"pdp"`
}
You can print just the ID's:
for i := 0; i < len(attributes.Pdp.Units); i++ {
// fmt.Println(reflect.TypeOf(attributes.Pdp.Units[i].Attributes))
fmt.Printf("ID: %s\n", attributes.Pdp.Units[i].Attributes[0].ID)
}

Go JSON Naming strategy about extends

My Go struct is like this:
type BaseModel struct {
Id string `json:"id"`
CreatedTime time.Time `json:"createdTime"`
UpdatedTime time.Time `json:"updatedTime"`
Deleted bool `json:"deleted"`
}
type Category struct {
BaseModel
Parent string `json:"parent"`
Name string `json:"name"`
IconClass string `json:"iconClass"`
Mark string `json:"mark"`
}
I want convert Category to JSON like this:
{
"id":"",
"deleted":"",
...
"parent":"",
"name":""
}
But when I use Go's json to convert it, it gives me this:
{
"Id":"",
"Deleted":"",
...
"parent":"",
"name":"",
...
}
What should I do now?
I use under code to convert:
// define
var menus []models.Category
// query from db
q.Filter("deleted__exact", false).All(&menus)
// serialize it
res, _ := json.Marshal(&menus)
s := string(res[:])
beego.Debug(s)
Please, add your convert code here. The code below works fine.
type BaseModel struct {
Id string `json:"id"`
CreatedTime time.Time `json:"createdTime"`
UpdatedTime time.Time `json:"updatedTime"`
Deleted bool `json:"deleted"`
}
type Category struct {
BaseModel
Parent string `json:"parent"`
Name string `json:"name"`
IconClass string `json:"iconClass"`
Mark string `json:"mark"`
}
func main() {
data, err := json.Marshal(Category{})
if err != nil {
return
}
fmt.Println(string(data[:]))
}
Output:
{"id":"","createdTime":"0001-01-01T00:00:00Z","updatedTime":"0001-01-01T00:00:00Z","deleted":false,"parent":"","name":"","iconClass":"","mark":""}

Marshaling []interface{} in Go

type A struct {
Id uint32 `json:"id"`
}
type B struct {
A
Title string `json:"title"`
}
type C struct {
Id uint32 `json:"id"`
Name string `json:"name"`
Arrays []interface{} `json:"arrays"`
}
Is this the correct way to marshal an array of interfaces?
Put arrays in double quotes json:"arrays"