Parse json body array sent in POST request and print - json

I am having one issue while reading the json array. Need help for below query.
Request Json :
{ "httpReq": {
"username": "1234567890",
"password": "1234567890",
"number": "123456"
}
}
Response Json :
{ "httpResp": {
"status": "Pass",
"message": "great"
}
}
Below was my code: If i am passing the json object below its working, but i need to send "httpReq" in json.
package main
import (
"encoding/json"
"fmt"
)
type people struct {
Username string `json:"username"`
Password string `json:"password"`
Number string `json:"number"`
}
type peopleread struct {
Collection []people
}
func main() {
text := `{
"username": "1234567890",
"password": "1234567890",
"number": "123456"
}`
textBytes := []byte(text)
//people1 := people{}
var people2 people
err := json.Unmarshal(textBytes, &people2)
if err != nil {
fmt.Println(err)
return
}
Username := people2.Username
Password := people2.Password
Number := people2.Number
fmt.Println(Username)
fmt.Println(Password)
fmt.Println(Number)
}

To unmarshal with httpReq field you have to handle this.
Create a struct to your wrap your request body like json
type HttpReq struct{
HttpReq people `json:"httpReq"`
}
Then use unmarshal
var httpReq HttpReq
err := json.Unmarshal(textBytes, &httpReq)
Full code in Go playground here

Related

Issue parsing JSON file with Go

I make a GET request, and receive a JSON file, that I cannot parse.
Here is the data I have to parse
{
"codeConv": "ACC00000321",
"start": "2019-07-01T00:00:00Z",
"end": "2019-08-21T00:00:00Z",
"details": [
{
"idPrm": "30000000123456",
"keys": [
{
"timestamp": "2019-07-01T00:00:00Z",
"value": 0
},
{
"timestamp": "2019-07-01T00:30:00Z",
"value": 0
},
...
]
},
{
"idPrm": "30000000123457",
"keys": [
{
"timestamp": "2019-07-01T00:00:00Z",
"value": 1
},
{
"timestamp": "2019-07-01T00:30:00Z",
"value": 2
},
...
]
}
]
}
Here are my objects:
type APIMain struct {
CodeConv string `json:"codeConv"`
Start string `json:"start"`
End []Keys `json:"end"`
Details []APIData `json:"details"`
}
//APIData match the data we receive from api
type APIData struct {
Prm string `json:"idPrm"`
Keys []Keys `json:"keys"`
}
type Keys struct {
Timestamp string `json:"timestamp"`
Value string `json:"value"`
}
and here is the method to get data with basic auth:
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
if login != "" && password != "" {
req.SetBasicAuth(login, password)
}
response, err := client.Do(req)
//defer response.Body.Close()
if err != nil {
return nil, err
}
if response.StatusCode != 200 {
fmt.Println(response.Body)
panic(response.Status)
}
err = json.NewDecoder(response.Body).Decode(&result)
fmt.Println("result", result) // result is empty array
How can I see if the problem is in a request, or if the problem is in parsing ?
I have get a response.Body object, but it needs to be decoded.
I fixed it using: https://mholt.github.io/json-to-go/
which generated this structure:
type AutoGenerated struct {
CodeConv string `json:"codeConv"`
Start time.Time `json:"start"`
End time.Time `json:"end"`
Details []struct {
IDPrm string `json:"idPrm"`
Keys []struct {
Timestamp time.Time `json:"timestamp"`
Value float64 `json:"value"`
} `json:"keys"`
} `json:"details"`
}
Thanks for your comments
Great time saver !

How to unmarshal JSON in to array of interface and use

I am having difficulty understanding how to correctly unmarshal some JSON data that goes in to an array of type inteface and then use it. I tried to make this example code as simple as possible to illustrate the problem I am having. The code can be found in the playground here: https://play.golang.org/p/U85J_lBJ7Zr
The output looks like:
[map[ObjectType:chair ID:1234 Brand:Blue Inc.] map[ID:5678
Location:Kitchen ObjectType:table]] { } false { } false
Code
package main
import (
"fmt"
"encoding/json"
)
type Chair struct {
ObjectType string
ID string
Brand string
}
type Table struct {
ObjectType string
ID string
Location string
}
type House struct {
Name string
Objects []interface{}
}
func main() {
var h House
data := returnJSONBlob()
err := json.Unmarshal(data, &h)
if err != nil {
fmt.Println(err)
}
fmt.Println(h.Objects)
s1, ok := h.Objects[0].(Table)
fmt.Println(s1, ok)
s2, ok := h.Objects[0].(Chair)
fmt.Println(s2, ok)
}
func returnJSONBlob() []byte {
s := []byte(`
{
"Name": "house1",
"Objects": [
{
"ObjectType": "chair",
"ID": "1234",
"Brand": "Blue Inc."
},
{
"ObjectType": "table",
"ID": "5678",
"Location": "Kitchen"
}
]
}
`)
return s
}
I'm not sure if this is practical, since this is a simplified version of your scenario. However, one way to do this is combine the two object types to a new one, Object, and then unmarshal them directly to Object instead of using interface{}:
package main
import (
"encoding/json"
"fmt"
)
type Object struct {
ObjectType string
ID string
Brand string
Location string
}
type House struct {
Name string
Objects []Object
}
func returnJSONBlob() []byte {
s := []byte(`
{
"Name": "house1",
"Objects": [
{
"ObjectType": "chair",
"ID": "1234",
"Brand": "Blue Inc."
},
{
"ObjectType": "table",
"ID": "5678",
"Location": "Kitchen"
}
]
}
`)
return s
}
func main() {
var h House
data := returnJSONBlob()
err := json.Unmarshal(data, &h)
if err != nil {
fmt.Println(err)
}
fmt.Println(h.Objects[0].Brand)
fmt.Println(h.Objects[1].Location)
}
Prints:
Blue Inc.
Kitchen
Example here: https://play.golang.org/p/91F4UrQlSjJ

Go json.Unmarshall() works with single entity but not with slice

I'm using Go for a simple http client. Here's the entity I'm unmarshalling:
type Message struct {
Id int64
Timestamp int64
Text string
Author User
LastEdited int64
}
type User struct {
Id int64
Name string
}
A single entity looks like this in JSON:
{
"text": "hello, can you hear me?",
"timestamp": 1512964818565,
"author": {
"name": "andrea",
"id": 3
},
"lastEdited": null,
"id": 8
}
Go/json has no problem unmarshalling the single entity:
var m Message
err = json.Unmarshal(body, &m)
if err != nil {
printerr(err.Error())
}
println(m.Text)
However, if the return of the endpoint is multiple entities:
[
{
"text": "hello, can you hear me?",
"timestamp": 1512964800981,
"author": {
"name": "eleven",
"id": 4
},
"lastEdited": null,
"id": 7
}
]
And I change my corresponding Unmarshall to work on a slice of structs, Go throws an error:
var m []Message
err = json.Unmarshal(body, &m)
if err != nil {
printerr(err.Error()) // unexpected end of JSON input
}
for i := 0; i < len(m); i++ {
println(m[i].Text)
}
What gives?
Works fine for me (try it on playground), where are you getting the payload data from? sounds like that's truncating it.
package main
import (
"encoding/json"
"fmt"
)
type Message struct {
Id int64
Timestamp int64
Text string
Author User
LastEdited int64
}
type User struct {
Id int64
Name string
}
func main() {
body := []byte(`[
{
"text": "hello, can you hear me?",
"timestamp": 1512964800981,
"author": {
"name": "eleven",
"id": 4
},
"lastEdited": null,
"id": 7
}
]`)
var m []Message
err := json.Unmarshal(body, &m)
if err != nil {
fmt.Printf("error: %v") // unexpected end of JSON input
}
for i := 0; i < len(m); i++ {
fmt.Println(m[i].Text)
}
}
running it gives this output
hello, can you hear me?

Having trouble decoding JSON response [duplicate]

This question already has answers here:
My structures are not marshalling into json [duplicate]
(3 answers)
Closed 7 years ago.
This is my first attempt at Go and I feel I'm missing something important here. Trying to decode a JSON message from a webservice but the output I'm getting is:
{response:{requests:[]}}
All I'm really interested in is the data within the request node. My for-loop obviously isn't getting called because the array is empty. I feel like my structs need to be declared exactly as they appear in the webservice?
Sample JSON:
{
"response": {
"requests": [
{
"request": {}
},
{
"request": {
"id": 589748,
"image_thumbnail": "",
"description": "Blah blah",
"status": "received",
"user": "test"
}
}
],
"count": "50",
"benchmark": 0.95516896247864,
"status": {},
"debug": {}
}
}
type Request struct {
id int `json:"id"`
description string `json:"description"`
user string `json:"user"`
}
type Requests struct {
request Request `json:"request"`
}
type Response struct {
requests []Requests `json:"requests"`
}
type RootObject struct {
response Response `json:"response"`
}
url := "<webservice>"
req, err := http.NewRequest("GET", url, nil)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var r RootObject
decoder := json.NewDecoder(resp.Body)
decoder.Decode(&r)
fmt.Printf("%+v", r)
for _, req := range r.response.requests {
fmt.Printf("%d = %s\n", req.request.id, req.request.user)
}
Field names need to begin with upper case character to be exported identifiers.

How to decode json into structs

I'm trying to decode some json in Go but some fields don't get decoded.
See the code running in browser here:
What am I doing wrong?
I need only the MX records so I didn't define the other fields. As I understand from the godoc you don't need to define the fields you don't use/need.
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
import "encoding/json"
func main() {
body := `
{"response": {
"status": "SUCCESS",
"data": {
"mxRecords": [
{
"value": "us2.mx3.mailhostbox.com.",
"ttl": 1,
"priority": 100,
"hostName": "#"
},
{
"value": "us2.mx1.mailhostbox.com.",
"ttl": 1,
"priority": 100,
"hostName": "#"
},
{
"value": "us2.mx2.mailhostbox.com.",
"ttl": 1,
"priority": 100,
"hostName": "#"
}
],
"cnameRecords": [
{
"aliasHost": "pop.a.co.uk.",
"canonicalHost": "us2.pop.mailhostbox.com."
},
{
"aliasHost": "webmail.a.co.uk.",
"canonicalHost": "us2.webmail.mailhostbox.com."
},
{
"aliasHost": "smtp.a.co.uk.",
"canonicalHost": "us2.smtp.mailhostbox.com."
},
{
"aliasHost": "imap.a.co.uk.",
"canonicalHost": "us2.imap.mailhostbox.com."
}
],
"dkimTxtRecord": {
"domainname": "20a19._domainkey.a.co.uk",
"value": "\"v=DKIM1; g=*; k=rsa; p=DkfbhO8Oyy0E1WyUWwIDAQAB\"",
"ttl": 1
},
"spfTxtRecord": {
"domainname": "a.co.uk",
"value": "\"v=spf1 redirect=_spf.mailhostbox.com\"",
"ttl": 1
},
"loginUrl": "us2.cp.mailhostbox.com"
}
}}`
type MxRecords struct {
value string
ttl int
priority int
hostName string
}
type Data struct {
mxRecords []MxRecords
}
type Response struct {
Status string `json:"status"`
Data Data `json:"data"`
}
type apiR struct {
Response Response
}
var r apiR
err := json.Unmarshal([]byte(body), &r)
if err != nil {
fmt.Printf("err was %v", err)
}
fmt.Printf("decoded is %v", r)
}
As per the go documentaiton about json.Unmarshal, you can only decode toward exported fields, the main reason being that external packages (such as encoding/json) cannot acces unexported fields.
If your json doesn't follow the go convention for names, you can use the json tag in your fields to change the matching between json key and struct field.
Exemple:
package main
import (
"fmt"
"encoding/json"
)
type T struct {
Foo string `json:"foo"`
priv string `json:"priv"`
}
func main() {
text := []byte(`{"foo":"bar", "priv":"nothing"}`)
var t T
err := json.Unmarshal(text, &t)
if err != nil {
panic(err)
}
fmt.Println(t.Foo) // prints "bar"
fmt.Println(t.priv) // prints "", priv is not exported
}
You must Uppercase struct fields:
type MxRecords struct {
Value string `json:"value"`
Ttl int `json:"ttl"`
Priority int `json:"priority"`
HostName string `json:"hostName"`
}
type Data struct {
MxRecords []MxRecords `json:"mxRecords"`
}
http://play.golang.org/p/EEyiISdoaE
The encoding/json package can only decode into exported struct fields. Your Data.mxRecords member is not exported, so it is ignored when decoding. If you rename it to use a capital letter, the JSON package will notice it.
You will need to do the same thing for all the members of your MxRecords type.