Unable to decode the JSON response - json

I have the following response from a graph api
{
"data": [
{
"name": "Mohamed Galib",
"id": "502008940"
},
{
"name": "Mebin Joseph",
"id": "503453614"
},
{
"name": "Rohith Raveendranath",
"id": "507482441"
}
],
"paging": {
"next": "https://some_url"
}
}
I have a struct as follows
type Item struct {
Name, Id string
}
I wanted to parse the response and get an array of Item, How do I do that?

You need to update your struct like so:
type Item struct {
Name string `json:"name"`
Id string `json:"id"`
}
and add a struct to represent the wrapper:
type Data struct {
Data []Item `json:"data"`
}
You can then use json.Unmarshal to populate a Data instance.
See the example in the docs.

Related

Unwinding nested data responses into structs when a slice is part of the response

I'd like to get some input into how you would all go about unwinding nested response data into custom structs. Below is an example of the data i'm being returned. I'm trying to get to the user data.
{
"_links": {
"self": {
"href": "/api/v2/user-search/default/test?after=1585612800000&limit=20&offset=0&q=johnsmith%40test.com",
"type": "application/json"
}
},
"totalCount": 1,
"items": [
{
"lastPing": "2020-04-30T02:56:10.430867577Z",
"environmentId": "xxxx",
"ownerId": "xxxx",
"user": {
"key": "johnsmith#test.com",
"email": "johnsmith#test.com",
"firstName": "john",
"lastName": "smith"
},
"_links": {
"parent": {
"href": "/api/v2/users/default/test",
"type": "application/json"
},
"self": {
"href": "/api/v2/users/default/test/johnsmith#test.com",
"type": "application/json"
},
"settings": {
"href": "/api/v2/users/default/test/johnsmith#test.com/flags",
"type": "text/html"
},
"site": {
"href": "/default/test/users/johnsmith#test.com",
"type": "text/html"
}
}
}
]
}
Currently I'm doing the below
respData := map[string][]map[string]map[string]interface{}{}
json.Unmarshal(respBody, &respData)
userData := respData["items"][0]["user"]
I'd love to be able to unmarshal it into a custom struct but I can't seem to get it to work. The nested slice that the user object sits within is what keeps throwing me off.
type User struct {
Key string `json:"key"`
Email string `json:"email"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
type LinkInfo struct {
Href string `json:"href"`
Type string `json:"type"`
}
type Item struct {
LastPing time.Time `json:"lastPing"`
EnvironmentID string `json:"environmentId"`
OwnerID string `json:"ownerId"`
User User `json:"user"`
Links LinkInfo `json:"_links"`
Self LinkInfo `json:"self"`
Settings LinkInfo `json:"settings"`
Parent LinkInfo `json:"parent"`
Site LinkInfo `json:"site"`
}
type ItemDetails struct {
Links LinkInfo `json:"_links"`
TotalCount int `json:"total_count"`
Items []Item
}
Can you try this?
https://play.golang.org/p/S_CUN0XEh-d
From what you mentioned it sounds like you were on the right track. Your JSON is pretty large, so let me give you a smaller example similar to the part you mentioned you're having trouble with (the user object inside the items list).
type response struct {
TotalCount int `json:"totalCount"`
Items []*itemStruct `json:"items"`
}
type itemStruct struct {
LastPing string `json:"lastPing"`
User *userStruct `json:"user"`
}
type userStruct struct {
Key string `json:"key"`
}
Basically to map to a JSON list of objects, just put a field like this in your struct: Objects []*structWhichMapsToMyObject
Edit: Here's the code running in Go Playground: https://play.golang.org/p/EvSvv-2s8y8
If you want this:
"user": {
"key": "johnsmith#test.com",
"email": "johnsmith#test.com",
"firstName": "john",
"lastName": "smith"
}
Declare a matching Go struct:
type User struct {
Key string `json:"key"`
Email string `json:"email"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
Then, since the user's parent object looks like this:
"items": [
{
"lastPing": "2020-04-30T02:56:10.430867577Z",
"environmentId": "xxxx",
"ownerId": "xxxx",
"user": { ... },
"_links": { ... }
}
]
you also need to declare a matching Go struct for that (you can omit fields you don't need):
type Item struct {
User User `json:"user"`
}
and then the parent of the parent:
{
"_links": {
"self": {
"href": "/api/v2/user-search/default/test?after=1585612800000&limit=20&offset=0&q=johnsmith%40test.com",
"type": "application/json"
}
},
"totalCount": 1,
"items": [ ... ]
}
and the matching Go struct for the grandparent, again, include only the fields you need:
type ResponseData struct {
Items []Item `json:"items"`
}
Once you have this you can decode the json into an instance of ResponseData:
var rd ResponseData
if err := json.Unmarshal(data, &rd); err != nil {
panic(err)
}
for _, item := range rd.Items {
fmt.Println(item.User)
}
https://play.golang.com/p/7yavVSBcHQP

Nested Go Structs for JSON marshaling with optional structs

I'm trying to initialize a nested struct to then marshal into json for an API response. The challenge I'm hitting is one of the components (a slice of structs) can have n number of members but of one of two possible types (text, image).
The JSON I want to create looks like this:
{
"messages": [
{
"message_parts": [
{
"text": {
"content": "dfdffd"
}
},
{
"image": {
"url": "https://image.jpg"
}
}
],
"actor_id": "44444444",
"actor_type": "agent"
}
],
"channel_id": "44444444",
"users": [
{
"id": "44444444"
}
]
}
In the message_parts slice, that can contain at least one of text or image but possibly one of each.
My structs look like this currently:
Type messagePayload struct {
Messages []Messages `json:"messages"`
Status string `json:"status,omitempty"`
ChannelID string `json:"channel_id"`
Users []Users `json:"users"`
}
type Messages struct {
MessageParts []MessageParts `json:"message_parts"`
ActorID string `json:"actor_id"`
ActorType string `json:"actor_type"`
}
type Users struct {
ID string `json:"id"`
}
type Text struct {
Content string `json:"content,omitempty"`
}
type MessageParts struct {
Text *Text `json:"text,omitempty"`
Image *Image `json:"image,omitempty"`
}
type Image struct {
URL string `json:"url,omitempty"`
}
I'm really struggling to initialize this in a way that not show up in the json if they're not present.
here's where I'm at but it obviously doesn't work:
payload := &messagePayload{
Messages: []Messages{
{
MessageParts: []MessageParts{
{
&Text{
Content: text,
},
},
{
&Image{
URL: mediaurl,
},
},
},
ActorID: agentID,
ActorType: "agent",
}},
ChannelID: channelid,
Users: []Users{
{
ID: user,
},
},
}
EDIT:
Thanks to hint below and a few other findings, I've found the best way is to initalize the payload and then add the slices for text and images as needed:
https://play.golang.org/p/Pmmv00spcI6
As noted above, I was able to find a solution- you need to initialize the payload without the text or image data, then append them to the MessageParts slice:
package main
import (
"encoding/json"
"fmt"
)
type messagePayload struct {
Messages []Messages `json:"messages"`
Status string `json:"status,omitempty"`
ChannelID string `json:"channel_id"`
Users []Users `json:"users"`
}
type Messages struct {
MessageParts []MessageParts `json:"message_parts"`
ActorID string `json:"actor_id"`
ActorType string `json:"actor_type"`
}
type Users struct {
ID string `json:"id"`
}
type Text struct {
Content string `json:"content,omitempty"`
}
type MessageParts struct {
Text *Text `json:"text,omitempty"`
Image *Image `json:"image,omitempty"`
}
type Image struct {
URL string `json:"url,omitempty"`
}
func main() {
payload := &messagePayload{
Messages: []Messages{
{
MessageParts: []MessageParts{
},
ActorID: "id",
ActorType: "agent",
}},
ChannelID: "cid",
Users: []Users{
{
ID: "user1",
},
},
}
var text= new(MessageParts)
text.Text = &Text{Content: "LOL"}
var image = new(MessageParts)
image.Image= &Image{URL: "https://"}
payload.Messages[0].MessageParts = append(payload.Messages[0].MessageParts, *text)
payload.Messages[0].MessageParts = append(payload.Messages[0].MessageParts, *image)
m, err := json.Marshal(payload)
if err != nil {
fmt.Println("Error, ", err)
return
}
fmt.Println(string(m))
}

json object with nested structures in golang

I have the following json object that I am trying to represent with Go as a type JsonObject struct
and pass it back in its original json so that I can return the json as an api endpoint. Any advice/example?
[{
"time": 173000,
"id": "VLSuEE5m1kmIhgE7ZhHDFe",
"height": "",
"DATASTRUCTURE": {
},
"language": "en",
"size": 0,
"url": "http://www.gstatic.com/play.m3u8",
"type": "vid",
"definitionid": "h264",
"reference": "PAN-EN",
"content": "This is some content",
"revisiondate": "2017-11-29T00:00:00",
"data": {
},
"id": "BBBB3424-153E-49DE-4786-013B6611BBBB",
"thumbs": {
"32": "https://www.gstatic.com/images?q=tbn:ANd9GcRj",
"64": "https://www.gstatic.com/images?q=tbn:DPd3GcRj"
},
"title": "Cafeteria",
"hash": "BBBB5d39bea20edf76c94133be61BBBB"
}]
You can use https://mholt.github.io/json-to-go/ to generate struct for the given json schema.
For example, json given in the question can be represented like:
type AutoGenerated []struct {
Time int `json:"time"`
ID string `json:"id"`
Height string `json:"height"`
DATASTRUCTURE struct {
} `json:"DATASTRUCTURE"`
Language string `json:"language"`
Size int `json:"size"`
URL string `json:"url"`
Type string `json:"type"`
Definitionid string `json:"definitionid"`
Reference string `json:"reference"`
Content string `json:"content"`
Revisiondate string `json:"revisiondate"`
Data struct {
} `json:"data"`
Thumbs struct {
Num32 string `json:"32"`
Num64 string `json:"64"`
} `json:"thumbs"`
Title string `json:"title"`
Hash string `json:"hash"`}
Hope this helps!

JSON to struct conversion

This is the struct I have:
type Resource struct {
Name string `json:"name"`
Ranges struct {
Range []struct {
Begin int `json:"begin"`
End int `json:"end"`
} `json:"range"`
} `json:"ranges,omitempty"`
Role string `json:"role,omitempty"`
Type string `json:"type"`
Scalar Scalar `json:"scalar,omitempty"`
}
I don't know how to make fields in the JSON not null. For example, struct Range like that:
{
"name": "cpus",
"ranges": {
"range": null
},
"type": "SCALAR",
"scalar": {
"value": 1
}
}, {
"name": "mem",
"ranges": {
"range": null
}
a way to do that is assign range as *string and then you should compare it with nil or not, if not nil convert it to string and marshall it again
That changes struct is resolved my problem:
type Resource struct {
Name string `json:"name"`
Ranges *Ranges `json:"ranges,omitempty"`
Role string `json:"role,omitempty"`
Type string `json:"type"`
Scalar *Scalar `json:"scalar,omitempty"`
}
assuming that you want to marshal the structs in your question and get a json output that looks like this:
{
"name": "cpus",
"ranges": {
"range": []
},
"type": "SCALAR",
"scalar": {
"value": 1
}
},
{
"name": "mem",
"ranges": {
"range": []
}
}
In golang slices [] are a reference type, that are backed by an array.
You can read up on the internals of slices here: https://blog.golang.org/go-slices-usage-and-internals
Basically the reason that you are getting null in the output is because you have not instantiated the slice, the slice is essentially a pointer, and that pointer is nil.
Create a new empty slice, like []Range{} and assign that to the field in Resource that is currently null in the json, and instead of a nil pointer, you will have an empty slice that will be marshalled as [] and not null.

How do I parse a nested array in a nested JSON object in Golang?

I have a JSON:
{
"data": [
{
"id": 1,
"values": [
[
{
"id": "11",
"keys": [
{
"id": "111"
}
]
}
]
]
}
]
}
I want to parse "values" and "keys" into structs, but I don't known what type should i use in "Data"?:
type Value struct {
Id string `json:"id"`
Keys []Key `json:"keys"`
}
type Key struct {
Id string `json:"id"`
}
type Result struct {
Data []Data `json:"data"`
}
type Data struct {
Id int `json:"id"`
Values []???? `json:"values"`
}
I would be grateful for any help. Thanks.
If you look carefully at your json. you have an array in an array...
...
"values": [
[...
If this is intended then the type of values is:
[][]Value
to represent the two arrays, else remove the array nesting and it becomes:
[]Value
Runnable Example: https://play.golang.org/p/UUqQR1KSwB
type Basic struct {
ID string `json:"id"`
}
type Inner struct {
ID string `json:"id"`
Keys []Basic `json:"keys"`
}
type Middle struct {
ID int `json:"id"`
Values []Inner `json:"values"`
}
type Final struct {
Data []Middle `json:"data"`
}