Error while converting json to struct from Go - mysql

func MakeMap(w http.ResponseWriter, r *http.Request) {
// userInfo := context.Get(r, "userInfo").(model.User)
type _getData struct {
Title string `json:"title"`
Tag []string `json:"tag"`
}
var getData _getData
err := json.NewDecoder(r.Body).Decode(&getData)
if err != nil {
panic(err.Error())
}
fmt.Print(getData)
}
When I run the above code, I get the following error
2021/08/24 13:56:54 http: panic serving 127.0.0.1:50619: runtime error: invalid memory address or nil pointer dereference
goroutine 23 [running]:
net/http.(*conn).serve.func1(0x140001e9180)
/usr/local/go/src/net/http/server.go:1824 +0x108
panic(0x10505b860, 0x10522f240)
/usr/local/go/src/runtime/panic.go:971 +0x3f4
traveling/controller/mapController.MakeMap(0x1050b5630, 0x140001f40e0, 0x1400018aa00)
/Users/choeyunseog/traveling/traveling/controller/mapController/mapController.go:20 +0x3c
I've just started studying, I'm not sure why I'm having this problem, please help
err := json.NewDecoder(r.Body).Decode(&getData)
I get the following error when i change code line 20 like above
2021/08/24 14:16:44 http: panic serving 127.0.0.1:51396: invalid character '-' in numeric literal
goroutine 23 [running]:
net/http.(*conn).serve.func1(0x140001e9360)
/usr/local/go/src/net/http/server.go:1824 +0x108
panic(0x100d85d00, 0x14000206070)
/usr/local/go/src/runtime/panic.go:971 +0x3f4
traveling/controller/mapController.MakeMap(0x100df1630, 0x140001f40e0, 0x1400018aa00)
/Users/choeyunseog/traveling/traveling/controller/mapController/mapController.go:24 +0x194
net/http.HandlerFunc.ServeHTTP(0x100de75d8, 0x100df1630, 0x140001f40e0, 0x1400018aa00)
/usr/local/go/src/net/http/server.go:2069 +0x40

To get the multipart form data from a POST/PUT/PATCH request's body you can use the ParseMultipartForm method to parse the body and then access the data through the PostForm field. Or you can use FormValue to get just the first value associated with the form's field.
maxMemory := 32<<20
if err := r.ParseMultipartForm(maxMemory); err != nil {
panic(err)
}
fmt.Println(_getData{
Title: r.FormValue("title"), // FormValue returns string
Tag: r.PostForm["tag[]"], // PostForm is a map of []string
})

You can use to parse form data into json like annotated struct using package github.com/senpathi/paramex. Struct fields must be annotated with param keyword and tag name is key of the form data.
your struct should be as below.
type _getData struct {
Title string `param:"title"`
Tag []string `param:"tag[]"`
}
This is the updated MakeMap handler function for your postman request mentioned in the question
func MakeMap(w http.ResponseWriter, r *http.Request) {
// userInfo := context.Get(r, "userInfo").(model.User)
type _getData struct {
Title string `param:"title"`
Tag []string `param:"tag[]"`
}
// this needed because u send data from Postman as multipart/form-data
maxMemory := 32<<20
if err := r.ParseMultipartForm(int64(maxMemory)); err != nil {
panic(err)
}
var getData _getData
extractor := paramex.NewParamExtractor()
err := extractor.ExtractForms(&getData, r)
if err != nil {
panic(err.Error())
}
fmt.Print(getData)
//Output: {defaultMap [travelling travelling2]}
}

Related

Golang json marshal and encoding give weird output

I am trying to customise error message for my db query . Following is what I am doing first I create struct Errormessage . Next if there is error in db.query I do this marshaling then encoding and return. But I end up getting this output "e30=" on my postman testing. What could be wrong I check and followed few examples are showing this mechanism ?
error1 := Errormessage{"Error in select"}
error1_enc,errEn := json.Marshal(error1)
if errEn != nil {
// if error is not nil
// print error
fmt.Println(errEn)
}
json.NewEncoder(w).Encode(error1_enc)
return
/
/ declaring a struct
type Errormessage struct{
// defining struct variables
errormessage string
}
func checkExistUser(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Println("File Name :", r.FormValue("email"))
result, err := db.Query("SELECT * from userDetailsss")
if err != nil {
//http.Error(w, err, 500)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(400)
fmt.Println(err)
error1 := Errormessage{"Error in select"}
error1_enc,errEn := json.Marshal(error1)
if errEn != nil {
// if error is not nil
// print error
fmt.Println(errEn)
}
json.NewEncoder(w).Encode(error1_enc)
return
//panic(err.Error())
}
// This part is how my db is defined and opened
var db *sql.DB
var err error
func main() {
db, err = sql.Open("mysql", "******##tcp(127.0.0.1:3306)/****")
if err != nil {
panic(err.Error())
}
defer db.Close()
router := mux.NewRouter()
router.HandleFunc("/", DoHealthCheck).Methods("POST")
router.HandleFunc("/checkExistUser", checkExistUser).Methods("POST")
log.Fatal(http.ListenAndServe(":8080", router))
}
There are two issues with your code:
You are json encoding the already json encoded error. This means that you are json encoding raw json bytes, which is the reason for the weird output.
Your Errormessage struct's field is unexported. Unexported fields will not be encoded by the encoding/json package.
To fix #1 you can do:
func checkExistUser(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Println("File Name :", r.FormValue("email"))
result, err := db.Query("SELECT * from userDetailsss")
if err != nil {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(400)
// use only Encode, no need to call json.Marshal
if err := json.NewEncoder(w).Encode(Errormessage{"Error in select"}); err != nil {
log.Println("failed to send reposnse:", err)
}
return
}
// ...
}
To fix #2 you can do:
type Errormessage struct {
// export the field, i.e. change it to start with an upper case letter
Errormessage string `json:"errormessage"`
}

Go reading map from json stream

I need to parse really long json file (more than million items). I don't want to load it to the memory and read it chunk by chunk. There's a good example with the array of items here. The problem is that I deal with the map. And when I call Decode I get not at beginning of value.
I can't get what should be changed.
const data = `{
"object1": {"name": "cattle","location": "kitchen"},
"object2": {"name": "table","location": "office"}
}`
type ReadObject struct {
Name string `json:"name"`
Location string `json:"location"`
}
func ParseJSON() {
dec := json.NewDecoder(strings.NewReader(data))
tkn, err := dec.Token()
if err != nil {
log.Fatalf("failed to read opening token: %v", err)
}
fmt.Printf("opening token: %v\n", tkn)
objects := make(map[string]*ReadObject)
for dec.More() {
var nextSymbol string
if err := dec.Decode(&nextSymbol); err != nil {
log.Fatalf("failed to parse next symbol: %v", err)
}
nextObject := &ReadObject{}
if err := dec.Decode(&nextObject); err != nil {
log.Fatalf("failed to parse next object")
}
objects[nextSymbol] = nextObject
}
tkn, err = dec.Token()
if err != nil {
log.Fatalf("failed to read closing token: %v", err)
}
fmt.Printf("closing token: %v\n", tkn)
fmt.Printf("OBJECTS: \n%v\n", objects)
}
TL,DR: when you are calling Token() method for a first time, you move offset from the beginning (of a JSON value) and therefore you get the error.
You are working with this struct (link):
type Decoder struct {
// others fields omits for simplicity
tokenState int
}
Pay attention for a tokenState field. This value could be one of (link):
const (
tokenTopValue = iota
tokenArrayStart
tokenArrayValue
tokenArrayComma
tokenObjectStart
tokenObjectKey
tokenObjectColon
tokenObjectValue
tokenObjectComma
)
Let's back to your code. You are calling Token() method. This method obtains first JSON-valid token { and changes tokenState from tokenObjectValue to the tokenObjectStart (link). Now you are "in-an-object" state.
If you try to call Decode() at this point you will get an error (not at beginning of value). This is because allowed states of tokenState for calling Decode() are tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue, i.e. "full" value, not part of it (link).
To avoid this you can just don't call Token() at all and do something like this:
dec := json.NewDecoder(strings.NewReader(dataMapFromJson))
objects := make(map[string]*ReadObject)
if err := dec.Decode(&objects); err != nil {
log.Fatalf("failed to parse next symbol: %v", err)
}
fmt.Printf("OBJECTS: \n%v\n", objects)
Or, if you want to read chunk-by-chunk, you could keep calling Token() until you reach "full" value. And then call Decode() on this value (I guess this should work).
After consuming the initial { with your first call to dec.Token(), you must :
use dec.Token() to extract the next key
after extracting the key, you can call dec.Decode(&nextObject) to decode an entry
example code :
for dec.More() {
key, err := dec.Token()
if err != nil {
// handle error
}
var val interface{}
err = dec.Decode(&val)
if err != nil {
// handle error
}
fmt.Printf(" %s : %v\n", key, val)
}
https://play.golang.org/p/5r1d8MsNlKb

How to pass struct as a parameter to a function

How can I do something Like this?
I am trying to pass a struct as a parameter to function in Go.
func handleEntityProperties(w http.ResponseWriter, r *http.Request) {
const sliceSize = 100
var entityProperties struct {
Instance string `json:"instance"`
Entities []struct {
Id string `json:"id"`
Properties map[string]string `json:"properties"`
Type string `json:"type"`
} `json:"entities"`
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
if !json.Valid([]byte(body)) {
fmt.Fprintf(w, "invalid json")
return
}
err = json.Unmarshal(body, &entityProperties)
sendData(entityProperties.Entities[0:100])
return
}
func sendData(entities struct) {
log.Println("Doing things with entities ", entities)
}
as you can see in code I am trying to send first 100 elements of entityProperties.Entities struct to a sendData. I know this is syntactically wrong.
Just declare your type outside of the functions:
type entity struct {
Id string `json:"id"`
Properties map[string]string `json:"properties"`
Type string `json:"type"`
}
And reuse it in handleEntityProperties() and in the signature of sendData():
func handleEntityProperties(w http.ResponseWriter, r *http.Request) {
const sliceSize = 100
var entityProperties struct {
Instance string `json:"instance"`
Entities []entity `json:"entities"`
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
if !json.Valid([]byte(body)) {
fmt.Fprintf(w, "invalid json")
return
}
err = json.Unmarshal(body, &entityProperties)
sendData(entityProperties.Entities[0:sliceSize])
return
}
func sendData(entities []entity) {
log.Println("Doing things with entities ", entities)
}
Also note that there is no guarantee that the client will send at least 100 entities, so you should check that else the slicing expression might result in a runtime panic:
max := 100
if len(entityProperties.Entities) < max {
max = len(entityProperties.Entities)
}
sendData(entityProperties.Entities[:max])
Also that check for invalid JSON is unnecessary: if the JSON is invalid, json.Unmarshal() will report a (non-nil) error and you'll know it.
Going further, you don't even have to read the complete body into memory (into a byte slice), you may use json.Decoder to read from it directly (without the intermediate memory buffer) like this:
dec := json.NewDecoder(r.Body)
if err := dec.Decode(&entityProperties); err != nil {
// handle error
}
And the final return statement is also unnecessary.
So an improved version may look like this:
func handleEntityProperties(w http.ResponseWriter, r *http.Request) {
var entityProperties struct {
Instance string `json:"instance"`
Entities []entity `json:"entities"`
}
dec := json.NewDecoder(r.Body)
if err := dec.Decode(&entityProperties); err != nil {
// handle error
http.Error(w, "invalid json", http.StatusBadRequest)
return
}
max := 100
if len(entityProperties.Entities) < max {
max = len(entityProperties.Entities)
}
sendData(entityProperties.Entities[:max])
}

Unmarshall PubSub Request Data []bytes with Go

I have an end-point that receives data from a Google PubSub request. As per this repo, the object is as so:
type pushRequest struct {
Message struct {
Attributes map[string]string
Data []byte
ID string `json:"message_id"`
}
Subscription string
}
The Data field is consistently formatted as so:
type Data struct {
Key string `json:"key"`
Body string `json:"body"`
Meta map[string]interface{} `json:"meta"`
}
I can obviously unmarshal the JSON request with something like this:
f := &pushRequest{}
json.Unmarshal(msg, &f)
That leaves with the the []bytes field. Which I can do something like this to convert to a string, as per the docs
messages = append(messages, string(f.Message.Data))
Which doesn't help, since I need it as a struct.
I can Unmarshal the array again:
var m Data
json.Unmarshal(f.Message.Data, &m)
Have tried changing the field type in the pushRequest struct to Data without success. Blank...
Is there a way I can unpack things in a single pass? Doing it twice seems ridiculous.
If it's obvious, I just can't see it!
decoder := json.NewDecoder(r.Body)
psmsg := &PushRequest{}
decoderErr := decoder.Decode(&psmsg)
if decoderErr != nil {
// Error...
return
}
data := Data{}
unmarshalErr := json.Unmarshal([]byte(string(psmsg.Message.Data)), &data)
if unmarshalErr != nil {
// Error...
return
}
Here is a snippet from my cloud function, which serves as a pub/sub push endpoint. The key is that you first have to decode the body using the PushRequest struct. Next, you can transform the message data into a struct. According to the documentation, the Data field within Message is a base-64 encoded string, therefore you have to decode it first.
type PushRequest struct {
Message pubsub.PubsubMessage `json:"message"`
Subscription string `json:"subscription"`
}
type Example struct {
ID string `json:"id" firestore:"id"`
}
func HTTPEndpoint(w http.ResponseWriter, r *http.Request) {
var pr common.PushRequest
if err := json.NewDecoder(r.Body).Decode(&pr); err != nil {
log.Fatalf("Could not decode body: %v", err)
return
}
data, err := base64.StdEncoding.DecodeString(pr.Message.Data)
if err != nil {
log.Fatalf("Base64: %v", err)
return
}
var example Example
if err := json.Unmarshal(data, &example); err != nil {
log.Fatalf("Json: %v", err)
return
}
// Do something useful with the struct
}

Is there a simpler way to implement a JSON REST service with net/http?

I am trying to develop a REST service with net/http.
The service receives a JSON structure containing all the input parameters. I wonder if there is an easier and shorter way to implement the following:
func call(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
fmt.Printf("Error parsing request %s\n", err)
}
var buf []byte
buf = make([]byte, 256)
var n, err = r.Body.Read(buf)
var decoded map[string]interface{}
err = json.Unmarshal(buf[:n], &decoded)
if err != nil {
fmt.Printf("Error decoding json: %s\n", err)
}
var uid = decoded["uid"]
...
}
As you can see it requires quite a number of lines just to get to the extraction of the first parameter. Any ideas?
You don't need to call r.ParseForm if the body of the request will contain a JSON structure and you don't need any URL parameters.
You don't need the buffer either; you can use:
decoder := json.NewDecoder(r.Body)
And then:
error := decoder.Decode(decoded)
Putting it all together:
func call(w http.ResponseWriter, r *http.Request) {
values := make(map[string]interface{})
if error := json.NewDecoder(r.Body).Decode(&values); error != nil {
panic(error)
}
uid := values["uid"].(int)
}
It would be much nicer, though, if you could formally define the structure of the input that you're expecting in a struct type:
type UpdateUserInformationRequest struct {
UserId int `json:"uid"`
// other fields...
}
And use an instance of this struct instead of a more general map.