call json keys undeclared in golang - json

lets say i have my structure :
type LstBQ4422400 struct {
Sku string `json:"sku"`
Image string `json:"image"`
Nom string `json:"Nom"`
Prix float64 `json:"prix"`
Num00195866137462 string `json:"00195866137462"`
Num00195866137479 string `json:"00195866137479"`
Num00195866137486 string `json:"00195866137486"`
Num00195866137493 string `json:"00195866137493"`
Num00195866137509 string `json:"00195866137509"`
Num00195866137516 string `json:"00195866137516"`
Num00195866137523 string `json:"00195866137523"`
Num00195866137530 string `json:"00195866137530"`
Num00195866137547 string `json:"00195866137547"`
Num00195866137554 string `json:"00195866137554"`
Num00195866137561 string `json:"00195866137561"`
Num00195866137578 string `json:"00195866137578"`
Num00195866137585 string `json:"00195866137585"`
Num00195866137592 string `json:"00195866137592"`
Num00195866137608 string `json:"00195866137608"`
Num00195866137615 string `json:"00195866137615"`
Num00195866137622 string `json:"00195866137622"`
Num00195866137639 string `json:"00195866137639"`
Num00195866137646 string `json:"00195866137646"`
Num00195866137653 string `json:"00195866137653"`
Num00195866137660 string `json:"00195866137660"`
Num00195866137677 string `json:"00195866137677"`
Num00195866137684 string `json:"00195866137684"`
}
then my code :
data := `{"sku": "BQ4422-400", "image": "https://static.nike.com/a/images/t_default/d099eea8-f876-477a-8333-a84e9acd8584/chaussure-air-jordan-1-high-85.png", "Nom": "Chaussure Air Jordan 1 High '85", "prix": 189.99, "00195866137462": "35.5", "00195866137479": "36", "00195866137486": "36.5", "00195866137493": "37.5", "00195866137509": "38", "00195866137516": "38.5", "00195866137523": "39", "00195866137530": "40", "00195866137547": "40.5", "00195866137554": "41", "00195866137561": "42", "00195866137578": "42.5", "00195866137585": "43", "00195866137592": "44", "00195866137608": "44.5", "00195866137615": "45", "00195866137622": "45.5", "00195866137639": "46", "00195866137646": "47", "00195866137653": "47.5", "00195866137660": "48.5", "00195866137677": "49.5", "00195866137684": "50.5"}`
var shoe LstBQ4422400
json.Unmarshal([]byte(data), &shoe)
the problem is i want to call a key this way : shoe.aStringIGotusingAList ,aStringIGotusingAList refers to a number like 00195866137684, so i get 50.5.
it doesnt let me put another thing than the key declared

The names of the members of the struct (the structs "fields") can be anything you want as long as you specify the "json" name using the struct tag. So using your example you could write the struct this way...
type LstBQ4422400 struct {
Sku string `json:"sku"`
Image string `json:"image"`
Nom string `json:"Nom"`
Prix float64 `json:"prix"`
...
AStringIGotusingAList string `json:"00195866137684"`
}
You will need to capitalize the fields you want to use with the stdlib json package because it only works with exported members (capitalized).
You can see a complete example here: https://go.dev/play/p/4XsKcdEz6R9

Related

Cannot Unmarshal JSON String to struct in Go

I have a string in my Go module which is the body of a HTTP response. it looks something like this:
bodyString = `{"firstname": "foo", "lastname": "bar", "username": "foobar"}`
I want to convert it to the following Go struct:
type Params struct {
FirstName string
LastName string
Username string
PasswordHash string
EmailAddress string
}
I attempt to do so using the following:
var jsonMap map[string]interface{}
json.Unmarshal([]byte(bodyString), &jsonMap)
paramsIn.FirstName = jsonMap["firstname"].(string)
paramsIn.LastName = jsonMap["lastname"].(string)
paramsIn.Username = jsonMap["username"].(string)
paramsIn.PasswordHash = jsonMap["passwordhash"].(string)
paramsIn.EmailAddress = jsonMap["emailaddress"].(string)
However the unmarshal fails to match the data in the string to the appropriate keys. i.e. what is stored in the jsonMap variable is only empty strings.
I clearly am doing something wrong and I haven't worked with json in Go very much. If any one can help or show me the correct way to unmarshal json data from a string that would be great, thanks.
Golang will convert your struct's field name (CammelCase) to snake_case (default). So, if you have struct like :
type Params struct {
FirstName string
LastName string
Username string
PasswordHash string
EmailAddress string
}
The JSON from the struct will be :
{
"first_name":"bla",
"last_name":"bla",
"user_name":"bla",
"password_hash":"ewedsads",
"email_address":"bla#gmail.com"
}
But you can customize the JSON field name by json tag, example :
type Params struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Username string `json:"username"`
PasswordHash string `json:"passwordhash"`
EmailAddress string `json:"emailaddress"`
}
Then you can change your code like this :
package main
import (
"encoding/json"
"fmt"
)
type Params struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Username string `json:"username"`
PasswordHash string `json:"passwordhash"`
EmailAddress string `json:"emailaddress"`
}
func main() {
paramsIn := Params{}
bodyString := `{"firstname": "foo", "lastname": "bar", "username": "foobar"}`
json.Unmarshal([]byte(bodyString), &paramsIn)
fmt.Println(paramsIn)
}
Use go tag like this:
type Params struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Username string `json:"username"`
PasswordHash string
EmailAddress string
}
This may not be the solution to everyone who is experience this problem, and you should check out the other answers on this post and other similar SO posts.
For me the issue was how the double quote character was being treated ("). My json string was being created from the body of a http response, which was being fed by a curl command in another terminal window. I was writing my curl commands in MacOS's standard text editor but I was in RTF (Rich Text Format) which formatted my " character as something else (“) (The difference is miniscule but it was enough to completely stump me for hours!). There is no issue with the code above once I used the proper double quote character in the http request body.
If I am unclear, please comment and I can clarify more.

Empty fields while unmarshalling depending on type

I have the following structs:
type Company struct {
Id uuid.UUID `json:"id"`
Name string `json:"name"`
Presentation string `json:"presentation"`
Jobs []*Job `json:"jobs"`
}
type Job struct {
Id uuid.UUID `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
When trying to unmarshal a json string that should match this struct hierarchy, some fields are filled in and others not. Mainly the uuid, but I also manage to get the title filled in the Jobs but not the description:
func main() {
s := `{"id": "2cc588a8-087a-4b81-a17f-3c9c35d2e958", "jobs": [{"id": "e1498403-82d8-47a9-b744-96b00c8b91e6", "title": "Qsd", "created_at": "2020-09-07T22:52:22.376857", "updated_at": "2020-09-07T22:52:22.376857", "description": "<p>sd</p>\n"}], "name": "NC", "presentation": "<p>qsdq</p>\n"}`
var company *Company
json.Unmarshal([]byte(s), &company)
log.Printf("%+v\n", company)
log.Printf("%+v\n", company.Jobs[0])
}
I'm not too surprised with the dates requiring a bit more formating but I don't get the inconsistencies on string fields. I have set up the code in the playground so everyone can test for themselves here.
The only real issue is that you are ignoring the error returned from json.Unmrshal. Because you are getting an error, you can't really rely on &company - it basically just gave up on it once it ran into an invalid date field, otherwise Description would have been fine:
https://play.golang.org/p/pxnIlmlPCq5

How to modify big JSON file

I have a large json file with multiple levels of nesting. Now I need to modify the value of each key in this file with the Go code. I know of two methods: the first is to obtain each key and then modify its value, but there is no doubt that this method is too complicated and prone to errors. The second method is to serialize the entire json file into a struct, then modify the struct field, and then deserialize it. However, this case needs to define a struct of several hundred lines, which is also very complicated.
Is there any other way?
for example my json is like this, but more bigger, 100+ lines :
{
"user": [{
"cdb_id":"",
"firstname":"Tom",
"lastname":"Bradley",
"phone":14155555555,
"email":"tom#gmail.com",
"address":[{
"street":"4343 shoemaker ave",
"city":"Brea",
"zip":"92821",
"country":"USA"
}],
"authenticators":[{
"name":"Lisa Hayden",
"phone":15625555555
},{
"name":"Pavan M",
"phone":17145555555
}],
"voice_sig":"242y5-4546-555kk54-437879ek545",
"voicesig_created_time":"2017-08-02T21:27:44+0000",
"status":"verified"
}]
}
I need modify "cdb_id"/"lastname"/"street"/"phone"/ "voice_sig".....all these keys' value, Except make a struct or get the keys' value one by one and modify, do i have any other way?
The new values for those keys will be POST request from Web Pages.
You can use json pointer:
https://godoc.org/github.com/go-openapi/jsonpointer
Or, you can read it in a map[string]interface{} and work your way through, but that gets tedious.
Now my way is use this website, switch my Json to struct, and modify one by one. But it just think this is not so good way, so i am eagering for a better way.
http://json2struct.mervine.net/
type MyJsonName struct {
User []struct {
Address []struct {
City string `json:"city"`
Country string `json:"country"`
Street string `json:"street"`
Zip string `json:"zip"`
} `json:"address"`
Authenticators []struct {
Name string `json:"name"`
Phone int `json:"phone"`
} `json:"authenticators"`
CdbID string `json:"cdb_id"`
Email string `json:"email"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Phone int `json:"phone"`
Status string `json:"status"`
VoiceSig string `json:"voice_sig"`
VoicesigCreatedTime string `json:"voicesig_created_time"`
} `json:"user"`
}

json marshal araylist in golang

Hi there I back to ask again
sorry if you guys think I lack of searching but been doing this for hours and I still don't get it why
I have a controller like this in Golang :
c3 := router.CreateNewControllerInstance("index", "/v4")
c3.Post("/insertEmployee", insertEmployee)
and using Postman to throw this arraylist request , the request is like this
[{
"IDEmployee": "EMP4570787",
"IDBranch": "ALMST",
"IDJob": "PRG",
"name": "Mikey Ivanyushin",
"street": "1 Bashford Point",
"phone": "9745288064",
"join_date": "2008-09-18",
"status": "fulltime"
},{
"IDEmployee": "EMP4570787",
"IDBranch": "ALMST",
"IDJob": "PRG",
"name": "Mikey Ivanyushin",
"street": "1 Bashford Point",
"phone": "9745288064",
"join_date": "2008-09-18",
"status": "fulltime"
}]
and also I have 2 Struct like this
type EmployeeRequest struct {
IDEmployee string `json: "id_employee"`
IDBranch string `json: "id_branch" `
IDJob string `json: "id_job" `
Name string `json: "name" `
Street string `json: "street" `
Phone string `json: "phone" `
JoinDate string `json: "join_date" `
Status string `json: "status" `
Enabled int `json: "enabled" `
Deleted int `json: "deletedstring"`
}
type ListEmployeeRequest struct {
ListEmployee []EmployeeRequest `json: "request"`
}
for some reason the problem start here , when I try to run my function to read the json that I send from Postman
here is the function that I try to run
func insertEmployee(ctx context.Context) {
tempReq := services.ListEmployeeRequest{}
temp1 := ctx.ReadJSON(&tempReq.ListEmployee)
var err error
if err = ctx.ReadJSON(temp1); config.FancyHandleError(err) {
fmt.Println("err readjson ", err.Error())
}
parsing, errParsing := json.Marshal(temp1)
fmt.Println("", string(parsing))
fmt.Print("", errParsing)
}
the problem occur on the line if err = ctx.ReadJSON(temp1); config.FancyHandleError(err)
it tell me that I got unexpected end of JSON input am I doing something wrong there when I throw the request from Postman? or I made a wrong validation code?
can someone tell me what to do next for me to be able to read the JSON that I throw from postman?
thanks for your attention and help , much love <3
You have multiple issues here:
Tag names don't match the JSON input, e.g. id_employee vs IDEmployee.
Your tag syntax is not correct, it shows when you run go vet, it should be json:"id_employee"
You don't need another List struct, if you use it your json should be {"requests":[...]}. Instead you can deserialize a slice:
var requests []EmployeeRequest
if err := json.Unmarshal([]byte(j), &requests); err != nil {
log.Fatal(err)
}
You can see a running version here: https://play.golang.org/p/HuycpNxE6k8
type EmployeeRequest struct {
IDEmployee string `json:"IDEmployee"`
IDBranch string `json:"IDBranch"`
IDJob string `json:"IDJob"`
Name string `json:"name"`
Street string `json:"street"`
Phone string `json:"phone"`
JoinDate string `json:"join_date"`
Status string `json:"status"`
Enabled int `json:"enabled"`
Deleted int `json:"deletedstring"`
}
some of json tags didn't match with fields.

Creating struct to read from API in Go

I'm working on a project and it is my first time using Go.
The project queries a number of APIs and for the most part I have had no trouble getting this working.
Coming from a PHP background, creating Go type definitions for my JSON responses is a little different.
I am stuck on one API, a Magento API, that returns a JSON response like so:
{
"66937": {
"entity_id": "66937",
"website_id": "1",
"email": "email#email.com",
"group_id": "1",
"created_at": "2017-08-11 02:09:18",
"disable_auto_group_change": "0",
"firstname": "Joe",
"lastname": "Bloggs",
"created_in": "New Zealand Store View"
},
"66938": {
"entity_id": "66938",
"website_id": "1",
"email": "email1#email.comm",
"group_id": "1",
"created_at": "2017-08-11 02:16:41",
"disable_auto_group_change": "0",
"firstname": "Jane",
"lastname": "Doe",
"created_in": "New Zealand Store View"
}
}
I have been using a tool, JSON-to-Go, to help me create the struct types, however it doesn't look quite right for this style of response:
type AutoGenerated struct {
Num0 struct {
EntityID string `json:"entity_id"`
WebsiteID string `json:"website_id"`
Email string `json:"email"`
GroupID string `json:"group_id"`
CreatedAt string `json:"created_at"`
DisableAutoGroupChange string `json:"disable_auto_group_change"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
CreatedIn string `json:"created_in"`
} `json:"0"`
Num1 struct {
EntityID string `json:"entity_id"`
WebsiteID string `json:"website_id"`
Email string `json:"email"`
GroupID string `json:"group_id"`
CreatedAt string `json:"created_at"`
DisableAutoGroupChange string `json:"disable_auto_group_change"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
CreatedIn string `json:"created_in"`
} `json:"1"`
}
All I am interested in is the inner JSON - the stuff to actually do with the customer. I am looping over this to extract some information.
How do I create the required struct to read from this?
I have looked at any number of documents or articles but they tend to use more simple JSON responses as examples.
For your JSON structure following might suit well.
Play Link: https://play.golang.org/p/ygXsdYALCb
Create a struct called Info or name you prefer also customize your field names as you like.
type Info struct {
EntityID string `json:"entity_id"`
WebsiteID string `json:"website_id"`
Email string `json:"email"`
GroupID string `json:"group_id"`
CreatedAt string `json:"created_at"`
DisableAutoGroupChange string `json:"disable_auto_group_change"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
CreatedIn string `json:"created_in"`
}
And create map of Info struct and the unmarshal it.
var result map[string]Info
if err := json.Unmarshal(jsonBytes, &result); err != nil {
fmt.Println(err)
}
fmt.Printf("%+v", result)
EDIT:
As asked in the comment, adding for example:
fmt.Println("Accessing unmarshal values:")
for key, info := range result {
fmt.Println("Key:", key)
fmt.Printf("Complete Object: %+v\n", info)
fmt.Println("Individual value, typical object field access:")
fmt.Println("EntityID:", info.EntityID)
fmt.Println("Email:", info.Email)
}
Well, first, I don't like the auto-generated struct definitions there. I would change that to look like this
type Customer struct {
EntityID string `json:"entity_id"`
WebsiteID string `json:"website_id"`
Email string `json:"email"`
GroupID string `json:"group_id"`
CreatedAt string `json:"created_at"`
DisableAutoGroupChange string `json:"disable_auto_group_change"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
CreatedIn string `json:"created_in"`
}
You may want to create a wrapper type
type Customers map[string]Customer
This should work with your json that you've provided. To put this together
customers := Customers{}
err := json.Unmarshal(jsonBytes, &customers)
Both #Xibz and #jeevatkm provided great solutions. However, in some cases, not all JSON structures can be unmarshalled into Go structures. You may have to define your own decoding functions.
You can also try gorilla's schema package if you have to define your own decoding function for particular data type or structures.
https://github.com/gorilla/schema