Parsing Json to Struct in Go doesn't work [duplicate] - json

This question already has answers here:
json.Marshal(struct) returns "{}"
(3 answers)
(un)marshalling json golang not working
(3 answers)
Printing Empty Json as a result [duplicate]
(1 answer)
json.Unmarshal json string to object is empty result [duplicate]
(1 answer)
json.Unmarshal not returning decoded data [duplicate]
(1 answer)
Closed 11 months ago.
I runned the bellow code to retrieve a json from api and parse the values to a struct to use the values, but the print appears in blank.
The json format is:
"user":{
"id":13,
"name":"xpto",
"email":"bla#blum.com.br",
"role":"partner"
},
"token":"hjhfsdhfjkhskfjhsjkfhjksdhfjkshfkjsoiwwsnskcnksjcjkscksjcksbsdsdjsdj"
}
and the code that i am running is:
package main
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
)
type resposta struct {
usuario usuario `json:"user"`
token string `json:"token"`
}
type usuario struct {
id string `json:"id"`
name string `json:"name"`
email string `json:"email"`
role string `json:"role"`
}
func main() {
values := map[string]string{"email": "blablum#xpto.com.br", "password": "senhaaaaa"}
jsonValue, _ := json.Marshal(values)
response, _ := http.Post("https://api.endereco.com.br/sessions", "application/json", bytes.NewBuffer(jsonValue))
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body)
println(body)
println(string(body))
var result resposta
json.Unmarshal(body, &result)
println("Resposta")
println(result.token)
println(result.token)
}
Any suggestion?

All your struct fields are unexported (they begin with a lowercase letter) and thus are considered "private." This is preventing the json package from seeing them with reflection. Export your fields by naming them with a Capital letter and it'll work.
Here's an example with some test data: https://go.dev/play/p/0lWdLtNuOr3

Related

How to convert escaped json into a struct [duplicate]

This question already has answers here:
decode json including json encoded strings
(1 answer)
Unmarshaling a stringified json
(1 answer)
Closed 1 year ago.
I am having trouble converting an escaped json object into a struct.
The main problem I am facing is the escaped json for the sources field.
The following data is how it's being saved.
{
"key": "123",
"sources": "{\"1a\":\"source1a\",\"2b\":\"source2b\",\"3c\":\"source3c\",\"default\":\"sourcex\"}"
}
type config struct {
Key string `json:"key" validate:"required"`
Sources ???? `json:"sources" validate:"required"`
}
I then will have a source value and would like to check if my value is found in the json.
If my value is "1a" return "source1a", etc.
I'm trying to write this in a unit test as well.
Some might do a custom unmarshal method, but I think it's easier just to do two passes:
package main
import (
"encoding/json"
"fmt"
)
const s = `
{
"key": "123",
"sources": "{\"1a\":\"source1a\",\"2b\":\"source2b\",\"3c\":\"source3c\",\"default\":\"sourcex\"}"
}
`
func main() {
var t struct{Key, Sources string}
json.Unmarshal([]byte(s), &t)
m := make(map[string]string)
json.Unmarshal([]byte(t.Sources), &m)
fmt.Println(m) // map[1a:source1a 2b:source2b 3c:source3c default:sourcex]
}

how to unmarshal simple json with lowercase member into a struct [duplicate]

This question already has an answer here:
Why struct fields are showing empty?
(1 answer)
Closed 2 years ago.
I have a simple struct with string and int.
When I unmarshal a json the struct members are not getting parsed if beginning with lowercase string .Even if I am using in the same package
package main
import (
"encoding/json"
"fmt"
)
type Bird struct {
Species string
Description string
lifespan int
}
func main() {
birdJson := `{"species": "pigeon","description": "likes to perch on rocks","lifespan": 9}`
var bird Bird
json.Unmarshal([]byte(birdJson), &bird)
fmt.Printf("Species: %s, Description: %s,lifespan: %d", bird.Species, bird.Description,bird.lifespan)
//Cant read the lifespan ??
}
lifespan int
needs to be
Lifespan int
you can't unmarshal into an unexported field

How to render a json string from bson document [duplicate]

This question already has answers here:
How to convert bson to json effectively with mongo-go-driver?
(1 answer)
convert result into JSON without structs using mongo-go-driver
(1 answer)
How can I get JSON from BSON without my keys all being named "Key"?
(1 answer)
Closed 3 years ago.
I am struggling to create a valid JSON string from a BSON document in Go for an API.
Let's say I have an object like this:
type MyObject struct {
Name string
}
I call my database which returns to me a cursor containing many documents as: [{"Name": "object_name"}, ...]
I am able to retrieve all the documents via a loop like
for cur.Next(ctx) {
var obj MyObject
err := cur.Decode(&obj)
//then display error if there's one
}
And now I would like to end up with a JSON string containing all the documents my database returned in order to send it via HTTP.
Because, if use I fmt.Println(obj)I end up with something like this: [{object1_name} {object2_name} ...] which is, according to me, not a valid format that I can use for an API.
I know json.Marshal(obj) can actually encode to valid JSON and I can decode it with os.Stdout.Write(obj) but I didn't manage to store this valid string in a variable. How can I manage to do this?
From Golang documentation for json package
package main
import (
"encoding/json"
"fmt"
)
func main() {
type ColorGroup struct {
ID int `json:"id"`
Name string `json:"name"`
Colors []string `json:"colors"`
}
group := ColorGroup{
ID: 1,
Name: "Reds",
Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
}
b, err := json.Marshal(group)
if err != nil {
fmt.Println("error:", err)
} else {
str := string(b)
fmt.Println("stringified json is:", str)
}
}
Output
stringified json is: {"id":1,"name":"Reds","colors":["Crimson","Red","Ruby","Maroon"]}
The json.Marshal return two values - a byte array and error
If error is nil then you can obtain the string by converting byte array to string using
str := string(b)

Why golang didn't marshal the json object? [duplicate]

This question already has answers here:
json.Marshal(struct) returns "{}"
(3 answers)
Closed 5 years ago.
I wonder why the following didn't marshall to json successfully? I am trying to use a very simple example to learn json package.
package main
import (
"encoding/json"
"fmt"
)
type Message struct {
username string `json:"name"`
message string `json:"message"`
}
func main() {
var m = Message{
username: "hello",
message: "world",
}
js, _ := json.Marshal(m)
fmt.Println(m)
fmt.Println(string(js))
}
username
message
start with a lowercase letter, meaning they are unexported (think private), and so are not visible to the encoding/json package. You need to export your fields, or implement the MarshalJSON() ([]byte, error) method and do it yourself.

unmarshal generic json in Go [duplicate]

This question already has answers here:
JSON and dealing with unexported fields
(2 answers)
(un)marshalling json golang not working
(3 answers)
json.Marshal(struct) returns "{}"
(3 answers)
Printing Empty Json as a result [duplicate]
(1 answer)
Parsing JSON in Golang doesn't Populate Object [duplicate]
(1 answer)
Closed 10 months ago.
I'm a new Go programmer (From Java) and I would like to reproduce a generic way which is esay to use in Java.
I want to create some function which allow me to do an Unmarshal on a JSON string in order to avoid code duplicity.
This is my current code which is not working :
type myStruct1 struct {
id string
name string
}
func (obj myStruct1) toString() string {
var result bytes.Buffer
result.WriteString("id : ")
result.WriteString(obj.id)
result.WriteString("\n")
result.WriteString("name : ")
result.WriteString(obj.name)
return result.String()
}
func main() {
content := `{id:"id1",name="myName"}`
object := myStruct1{}
parseJSON(content, object)
fmt.Println(object.toString())
}
func parseJSON(content string, object interface{}) {
var parsed interface{}
json.Unmarshal([]byte(content), &parsed)
}
This code, on run, returns me this :
id :
name :
Do you have any idea ?
Thanks
The issue is you want to write to a generic type? You probably want a string map. This works with BSON anyways:
var anyJson map[string]interface{}
json.Unmarshal(bytes, &anyJson)
You'll be able to access the fields like so:
anyJson["id"].(string)
Don't forget to type assert your values, and they must be the correct type or they'll panic. (You can read more about type assertions on the golang site)
To parse "generic JSON" when you have no idea what schema it has:
var parsed any
err := json.Unmarshal(jsonText, &parsed)
The returned any in parsed will be a map[string]any or []any or nil or single values float64, bool, string.
You can test the type and react accordingly.
import (
"encoding/json"
"fmt"
)
func test(jsonText []byte) {
// parsing
var parsed any
err := json.Unmarshal(jsonText, &parsed)
if err != nil {
panic(err) // malformed input
}
// type-specific logic
switch val := parsed.(type) {
case nil:
fmt.Println("json specifies null")
case map[string]any:
fmt.Printf("id:%s name:%s\n", val["id"], val["name"])
case []any:
fmt.Printf("list of %d items\n", len(val))
case float64:
fmt.Printf("single number %f\n", val)
case bool:
fmt.Printf("single bool %v\n", val)
case string:
fmt.Printf("single string %s\n", val)
default:
panic(fmt.Errorf("type %T unexpected", parsed))
}
}
Unmarshal will only set exported fields of the struct.
Which means you need to modify the json struct to use capital case letters:
type myStruct1 struct {
Id string
Name string
}
The reason behind this is that the json library does not have the ability to view fields using reflect unless they are exported.
You have to export your fields:
type myStruct1 struct {
Id string
Name string
}
See Exported Identifiers from documentation.
There are a few changes you need to make in your code to make it work:
The function json.Unmarshal can only set variables inside your struct which are exported, that is, which start with capital letters. Use something like ID and Name for your variable names inside myStruct1.
Your content is invalid JSON. What you actually want is {"ID":"id1","Name":"myName"}.
You're passing object to parseJSON but you're using parsed instead, not object. Make parseJSON receive a *myStruct (instead of an interface{}), and use that variable instead of parsed when unmarshalling the string. Also, always handle the error returns, like err := json.Unmarshal(content, object), and check err.
I'd suggest you to do the Golang Tour ;)
You can also set the file as an Object with dynamic properties inside another struct. This will let you add metadata and you read it the same way.
type MyFile struct {
Version string
Data map[string]interface{}
}