I'm working on an API client and I need to be able to send a nested JSON structure with a client.PostForm request. The issue I'm encountering is this:
reqBody := url.Values{
"method": {"server-method"},
"arguments": {
"download-dir": {"/path/to/downloads/dir"},
"filename": {variableWithURL},
"paused": {"false"},
},
}
When I try to go build
this, I get the following errors:
./transmission.go:17: syntax error: unexpected :, expecting }
./transmission.go:24: non-declaration statement outside function body
./transmission.go:26: non-declaration statement outside function body
./transmission.go:27: non-declaration statement outside function body
./transmission.go:29: non-declaration statement outside function body
./transmission.go:38: non-declaration statement outside function body
./transmission.go:39: syntax error: unexpected }
I'm wondering what the correct way to created a nested set of values in this scenario. Thanks in advance!
You are not using properly the url.Values
, according to the source code (url package, url.go):
// Values maps a string key to a list of values.
// It is typically used for query parameters and form values.
// Unlike in the http.Header map, the keys in a Values map
// are case-sensitive.
type Values map[string][]string
But arguments
is not compliant with the definition because the object of arguments
is not an array of strings.
I was able to figure this out on my own! The answer is to struct all-the-things!
type Command struct {
Method string `json:"method,omitempty"`
Arguments Arguments `json:"arguments,omitempty"`
}
type Arguments struct {
DownloadDir string `json:"download-dir,omitempty"`
Filename string `json:"filename,omitempty"`
Paused bool `json:"paused,omitempty"`
}
Then, when creating your PostForm:
jsonBody, err := json.Marshal(reqBody) // reqBody is a Command
if (err != nil) {
return false
}
req, err := http.NewRequest("POST", c.Url, strings.NewReader(string(jsonBody)))
Hope this helps!
I used NewRequest
as Connor mentions in his answer but using a struct
and then marshalling it seems an unnecessary step to me.
I passed my nested json string straight to strings.NewReader
:
import (
"net/http"
"strings"
)
reqBody := strings.NewReader(`{
"method": {"server-method"},
"arguments": {
"download-dir": {"/path/to/downloads/dir"},
"paused": {"false"},
},
}`)
req, err := http.NewRequest("POST", "https://httpbin.org/post", reqBody)
Hope it helps those who are stuck with Go's http PostForm which only accepts url.Values
as argument while url.Values
cannot generate nested json.