How to access embedded key values in a POST request

Viewed 76

I am making a a roulette REST API in Golang:

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "github.com/gorilla/mux"
)

func handleRequests() {
    // creates a new instance of a mux router
    myRouter := mux.NewRouter().StrictSlash(true)
    
    myRouter.HandleFunc("/spin/", handler).Methods("POST")
    log.Fatal(http.ListenAndServe(":10000", myRouter))
}

func handler(w http.ResponseWriter, r *http.Request) {

    reqBody, _ := ioutil.ReadAll(r.Body)

    s := string(reqBody)
    fmt.Println(s)
}

func main() {
    fmt.Println("Rest API v2.0 - Mux Routers")
    handleRequests()
}

main.go

And I am testing the POST method with a Python script:

import requests

url = 'http://localhost:10000/spin/'

myobj = {'bets':[
                {
                    'amount' : 10,
                    'position' : [0,1,2]
                },
                {
                    'amount' : 20,
                    'position' : [10]
                }
            ]
}

x = requests.post(url, data = myobj)

print(x.text)

test.py

When I run the test script. And the server receives my POST request. The request body is: bets=amount&bets=position&bets=amount&bets=position

The problem is that the values for the 'amount' and 'position' keys are not there.

My question is - how can I make/ handle POST requests so that I am able to access the values for the embedded keys 'amount' and 'position' in my handler function on the Go server, so that I can put this information into an instance of a struct.

2 Answers

The problem lies on the python side, if you print out the body/header of your request:

print requests.Request('POST', url, data=myobj).prepare().body
print requests.Request('POST', url, data=myobj).prepare().headers


# bets=position&bets=amount&bets=position&bets=amount
# {'Content-Length': '51', 'Content-Type': 'application/x-www-form-urlencoded'}

data uses x-www-form-urlencoded encoding, so expects a flat list of key/value pairs.

You probably want json to represent your data:

print requests.Request('POST', url, json=myobj).prepare().body
print requests.Request('POST', url, json=myobj).prepare().headers

# {"bets": [{"position": [0, 1, 2], "amount": 10}, {"position": [10], "amount": 20}]}
# {'Content-Length': '83', 'Content-Type': 'application/json'}

Fix:

x = requests.post(url, json = myobj) // `json` not `data`

Finally, it's worth checking the Content-Type header on the Go server-side to ensure you get the encoding you expect (in this case application/json).

I think you need a struct to unmarshal the data.I think this code could help you.

package main

import (
    "encoding/json"
    "fmt"
    "github.com/gorilla/mux"
    "io/ioutil"
    "log"
    "net/http"
)

type Body struct {

    Bets []Persion  `json:"bets"`
}
type Persion struct{
    Amount int  `json:"amount"`
    Position []int  `json:"position"`
}

func handleRequests() {
    // creates a new instance of a mux router
    myRouter := mux.NewRouter().StrictSlash(true)

    myRouter.HandleFunc("/spin/", handler).Methods("POST")
    log.Fatal(http.ListenAndServe(":10000", myRouter))
}

func handler(w http.ResponseWriter, r *http.Request) {

    reqBody, _ := ioutil.ReadAll(r.Body)
     bodyObj :=&Body{}
    err:=json.Unmarshal(reqBody,bodyObj)
    if err!=nil{
        log.Println("%s",err.Error())
    }
    //s := string(reqBody)
    fmt.Println(bodyObj.Bets[0].Amount)
}

func main() {
    fmt.Println("Rest API v2.0 - Mux Routers")
    handleRequests()
}
Related