So I have the following, which seems incredibly hacky, and I've been thinking to myself that Go has better designed libraries than this, but I can't find an example of Go handling a POST request of JSON data. They are all form POSTs.
Here is an example request: curl -X POST -d "{\"test\": \"that\"}" http://localhost:8082/test
And here is the code, with the logs embedded:
package main
import (
"encoding/json"
"log"
"net/http"
)
type test_struct struct {
Test string
}
func test(rw http.ResponseWriter, req *http.Request) {
req.ParseForm()
log.Println(req.Form)
//LOG: map[{"test": "that"}:[]]
var t test_struct
for key, _ := range req.Form {
log.Println(key)
//LOG: {"test": "that"}
err := json.Unmarshal([]byte(key), &t)
if err != nil {
log.Println(err.Error())
}
}
log.Println(t.Test)
//LOG: that
}
func main() {
http.HandleFunc("/test", test)
log.Fatal(http.ListenAndServe(":8082", nil))
}
There's got to be a better way, right? I'm just stumped in finding what the best practice could be.
(Go is also known as Golang to the search engines, and mentioned here so others can find it.)
I was driving myself crazy with this exact problem. My JSON Marshaller and Unmarshaller were not populating my Go struct. Then I found the solution at https://eager.io/blog/go-and-json:
After that, my Marshaller and Unmarshaller worked perfectly!
There are two reasons why
json.Decoder
should be preferred overjson.Unmarshal
- that are not addressed in the most popular answer from 2013:go 1.10
introduced a new method json.Decoder.DisallowUnknownFields() which addresses the concern of detecting unwanted JSON-inputreq.Body
is already anio.Reader
. Reading its entire contents and then performingjson.Unmarshal
wastes resources if the stream was, say a 10MB block of invalid JSON. Parsing the request body, withjson.Decoder
, as it streams in would trigger an early parse error if invalid JSON was encountered. Processing I/O streams in realtime is the preferred go-way.Addressing some of the user comments about detecting bad user input:
To enforce mandatory fields, and other sanitation checks, try:
Playground
Typical output:
I found the following example from the docs really helpful (source here).
The key here being that the OP was looking to decode
...in which case we would drop the
const jsonStream
, and replace theMessage
struct with thetest_struct
:Update: I would also add that this post provides some great data about responding with JSON as well. The author explains
struct tags
, which I was not aware of.Since JSON does not normally look like
{"Test": "test", "SomeKey": "SomeVal"}
, but rather{"test": "test", "somekey": "some value"}
, you can restructure your struct like this:...and now your handler will parse JSON using "some-key" as opposed to "SomeKey" (which you will be using internally).
Please use
json.Decoder
instead ofjson.Unmarshal
.You need to read from
req.Body
. TheParseForm
method is reading from thereq.Body
and then parsing it in standard HTTP encoded format. What you want is to read the body and parse it in JSON format.Here's your code updated.