Go Struct to decode expo push notification response? - json

I am making a service in go that sends push notification to Expo Backend. Once the http call is made Expo respond with bellow format(according to Expo):
{
"data": [
{
"status": "error" | "ok",
"id": string, // this is the Receipt ID
// if status === "error"
"message": string,
"details": JSON
},
...
],
// only populated if there was an error with the entire request
"errors": [{
"code": number,
"message": string
}]
}
And here is an provioded example of a response:
{
"data": [
{
"status": "error",
"message": "\\\"ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]\\\" is not a registered push notification recipient",
"details": {
"error": "DeviceNotRegistered"
}
},
{
"status": "ok",
"id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}
]
}
I created struct to decode the response.Now i get a error try to decode the reponse for the "details" field, No matter what type i use in my Struct. How can i deal with that field that expo mark as "JSON"?
import (
uuid "github.com/satori/go.uuid"
)
type PushResult struct {
Errors []ErrorDetails `json:"errors,omitempty"`
Datas []DataPart `json:"data,omitempty"`
}
type ErrorDetails struct {
Code int32 `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
type DataPart struct {
Status string `json:"status,omitempty"`
ID uuid.UUID `json:"id,omitempty"`
Message string `json:"message,omitempty"`
Details string `json:"details,omitempty"` //also tried map[string]string and interface{}
}
This is the struct i am using. i also tried this by looking at the example:
type DataPart struct {
Status string `json:"status,omitempty"`
ID uuid.UUID `json:"id,omitempty"`
Message string `json:"message,omitempty"`
Details struct{
Error string `json:"error"`} `json:"details,omitempty"`
}
But every time get an error like "json: cannot unmarshal object into Go struct field DataPart.data.details"

I just created you struct using your response exemple and it worked completly fine.
Playground
That said if you wana a better way of debugging an "unmarshal error" you can unwrap it. That way you can print aditional data.
var t *json.UnmarshalTypeError
if errors.As(err, &t) {
spew.Dump(t)
}
Example -> I changed the error type to integer so I can fake the error.
OBS: Note that your "Datas" is an array and only the 1st one have an error.

Related

Golang json collapse array of an object

In golang how can I collapse an array of an object when returning to json?
I'm not sure how to properly describe this problem but here is what I'm looking for.
{
"error_code": 422,
"errors": [
"email": [
"email is required"
]
]
}
Here's my code so far
type Error struct {
Email []string `json:"email"`
}
type Response struct {
ErrorCode int `json:"error_code"`
Errors []Error `json:"errors"`
}
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(422)
json.NewEncoder(w).Encode(Response{
ErrorCode: 422,
Errors: []Error{
Error{Email: []string{"email is required"}},
},
})
}
and the result is
{
"error_code": 422,
"errors": [
{
"email": [
"email is required"
]
}
]
}
Notice how errors is an array of object, how can I avoid that and directly have "email" array under "errors"?

Parse AWS ec2 DescribeInstanceStatusOutput JSON response using Golang

Hi all I am a beginner trying to learn Go. I am trying to get the status of my EC2 instance using AWS SDK with Golang. I was successfully able to get a JSON response for my instance. I am however, having issues trying to parse the JSON response to get the instance state.
The following is how I get the JSON response:
result, err := ec2Svc.DescribeInstanceStatus(input)
where input is of type ec2.DescribeInstanceStatusInput
The following is the JSON response I get:
{
"InstanceStatuses": [
{
"AvailabilityZone": "ap-southeast-2b",
"Events": null,
"InstanceId": "[VALIDIMAGEID]",
"InstanceState": {
"Code": 16,
"Name": "running"
},
"InstanceStatus": {
"Details": [
{
"ImpairedSince": null,
"Name": "reachability",
"Status": "passed"
}
],
"Status": "ok"
},
"OutpostArn": null,
"SystemStatus": {
"Details": [
{
"ImpairedSince": null,
"Name": "reachability",
"Status": "passed"
}
],
"Status": "ok"
}
}
],
"NextToken": null
}
I then parse the result which is of type DescribeInstanceStatusOutput to String and then pass it to the function parseJson where I attempt to parse the JSON.
result, err := ec2Svc.DescribeInstanceStatus(input)
if err != nil {
fmt.Println("Error", err)
} else {
parseJson(result.String())
//fmt.Printf("%v\n", result)
}
func parseJson(ec2StatusDescription string){
//var x string = ec2StatusDescription.String()
//fmt.Print(ec2StatusDescription)
data := []byte(ec2StatusDescription)
var instanceOutputs InstanceOutput
json.Unmarshal(data, &instanceOutputs)
fmt.Print(instanceOutputs.InstanceStatuses[0].InstanceState.Name)
}
type InstanceOutput struct {
InstanceStatuses [] InstanceStatuses
NextToken *string
}
type InstanceStatuses struct {
AvailabilityZone string
Events *string
InstanceId string
InstanceState InstanceState
InstanceStatus InstanceStatus
OutpostArn *string
SystemStatus SystemStatus
}
type InstanceState struct {
Code int
Name string
}
type InstanceStatus struct {
Details [] InstanceDetails
Status string
}
type InstanceDetails struct {
ImpairedSince *string
Name string
Status string
}
type SystemStatus struct {
Details [] InstanceDetails
Status string
}
I am trying to print the instance state but I keep getting index out of range, and this is because the JSON is not being parsed properly. What am i missing here that's causing the json to not parse correctly? Or am I getting it completely wrong in what I'm doing here? Any help would be highly appreciated.

Golang Json marshalling

type Status struct {
slug string `json:"slug"`
}
type Instance struct {
Slug string `json:"slug"`
Stat map[string]*Status `json:"status"`
}
This Json response is recieved for API call:
[ {
"status": {
"stop": false,
"traffic": true,
"label": null,
"dead": true,
"slug": "up",
},
"slug": "instances_raw",
"started_at": "15120736198",
"replacement": null
},
{
"status": {
"stop": false,
"traffic": true,
"label": null,
"dead": true,
"slug": "down",
},
"slug": "instance_raw2",
"started_at": "1512073194",
"replacement": null
}
]
I am trying to marshall json into above struct but running into issue:
instances := make([]Instance, 0)
res := api call return above json
body, _ := ioutil.ReadAll(res.Body)
json.Unmarshal(body, &instances)
fmt.Println("I am struct %s",instances)
It is marshalling into:
I am struct %s [{ map[stop:0xc42018e1b0 dead:0xc42018e1e0 label:<nil> running:0xc42018e220 down:0xc42018e150 traffic:0xc42018e180]}]
Can someone help me figure out why it is not marshalling as I am expecting?
Expected marshalling:
[{instances_raw map[slug:up]} {instances_raw2 map[slug:down]}]
The structs do not match the structure of the data. Perhaps you wanted this:
type Status struct {
Slug string `json:"slug"`
}
type Instance struct {
Slug string `json:"slug"`
Stat Status `json:"status"`
}
Output: [{instances_raw {up}} {instance_raw2 {down}}]
run it on the plaground
or this:
type Instance struct {
Slug string `json:"slug"`
Stat map[string]interface{} `json:"status"`
}
Output: [{instances_raw map[label: dead:true slug:up stop:false traffic:true]} {instance_raw2 map[slug:down stop:false traffic:true label: dead:true]}]
run it on the playground
Always check errors. The example JSON above is not valid and the json.Unmarshal function reports this error.

JSON string array without Keys into a GoLang struct

I am trying to parse JSON that is submitted from a POST request into a struct in a web service to send email. The following JSON is submitted in the body of the request.
{
"body": {
"template": "abctemplate.html",
"params": {
"name": "Chase",
"email": "1234#gmail.com"
}
},
"to": [
"abc#gmail.com",
"xyz#gmail.com"
],
"cc": [
"xxx#example.com",
"yyy#example.com"
],
"replyTo": {
"email": "aaa#gmail.com",
"name": "Jack"
},
"bcc": "ccc#gmail.com",
"subject": "Hello, world!"
}
This is mapped and read into the following struct
type emailData struct {
Body struct {
Template string `json:"template"`
Params map[string]string `json:"params"`
} `json:"body"`
To map[string]string `json:"To"` // TODO This is wrong
CC string `json:"cc"` // TODO this is wrong
ReplyTo struct {
Email string `json:"email"`
Name string `json:"name"`
}
BCC string `json:"bcc"`
Subject string `json:"subject"`
}
Both the 'to' and 'cc' JSON fields are string arrays of unknown length and do not have keys. Is there a way to map the string arrays into the struct fields? I've tried the two different ways where there are // TODO tags with no luck. Thanks!
Both cc and to are json arrays which you can unmarshal into Go slices without worrying about the length.
type emailData struct {
Body struct {
Template string `json:"template"`
Params map[string]string `json:"params"`
} `json:"body"`
To []string `json:"to"`
CC []string `json:"cc"`
ReplyTo struct {
Email string `json:"email"`
Name string `json:"name"`
}
BCC string `json:"bcc"`
Subject string `json:"subject"`
}
https://play.golang.org/p/Pi_5aSs922
Use the below to convert the json to struct in golang:
Json-goStruct
Take care of the maps, which might be go struct and vice-versa.

Unable to decode the JSON response

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.