How to retrieve form-data as map (like PHP and Ruby) in Go (Golang)
Is there a easier way to get my Form Array as an actual map in Golang like PHP does?
You can use the PostForm
member of the http.Request
type. It is of type url.Values
-- which is actually (ta-da) a map[string][]string
, and you can treat is as such. You'll still need to call req.ParseForm()
first, though.
if err := req.ParseForm(); err != nil {
// handle error
}
for key, values := range req.PostForm {
// [...]
}
Note that PostForm
is a map of lists of strings. That's because in theory, each field could be present multiple times in the POST body. The PostFormValue()
method handles this by implicitly returning the first of multiple values (meaning, when your POST body is &foo=bar&foo=baz
, then req.PostFormValue("foo")
will always return "bar"
).
Also note that PostForm
will never contain nested structures like you are used from PHP. As Go is statically typed, a POST form value will always be a mapping of string
(name) to []string
(value/s).
Personally, I wouldn't use the bracket syntax (contact[email]
) for POST field names in Go applications; that's a PHP specific construct, anyway and as you've already noticed, Go does not support it very well.
Should I retrieve the data one by one (Tedious as much and I may change the Form data at some point and recompile...) or iterate the whole thing as I've done in the 2nd example.
There's probably no correct answer for that. If you are mapping your POST fields to a struct with static fields, you'll have to explicitly map them at some point (or use reflect
to implement some magical auto-mapping).
I had a similar problem, so I wrote this function
func ParseFormCollection(r *http.Request, typeName string) []map[string]string {
var result []map[string]string
r.ParseForm()
for key, values := range r.Form {
re := regexp.MustCompile(typeName + "\\[([0-9]+)\\]\\[([a-zA-Z]+)\\]")
matches := re.FindStringSubmatch(key)
if len(matches) >= 3 {
index, _ := strconv.Atoi(matches[1])
for ; index >= len(result); {
result = append(result, map[string]string{})
}
result[index][matches[2]] = values[0]
}
}
return result
}
It turns a collection of form key value pairs into a list of string maps. For example, if I have form data like this:
Contacts[0][Name] = Alice
Contacts[0][City] = Seattle
Contacts[1][Name] = Bob
Contacts[1][City] = Boston
I can call my function passing the typeName of "Contacts":
for _, contact := range ParseFormCollection(r, "Contacts") {
// ...
}
And it will return a list of two map objects, each map containing keys for "Name" and "City". In JSON notation, it would look like this:
[
{
"Name": "Alice",
"City": "Seattle"
},
{
"Name": "Bob",
"City": "Boston"
}
]
Which incidentally, is exactly how I'm posting the data up to the server in an ajax request:
$.ajax({
method: "PUT",
url: "/api/example/",
dataType: "json",
data: {
Contacts: [
{
"Name": "Alice",
"City": "Seattle"
},
{
"Name": "Bob",
"City": "Boston"
}
]
}
})
If your form data key structure doesn't quite match mine, then I you could probably adapt the Regex that I'm using to suit your needs.