I'm a PHP Dev. But currently moving to Golang... I'm trying to retrieve data from a Form (Post method):
<!-- A really SIMPLE form -->
<form class="" action="/Contact" method="post">
  <input type="text" name="Contact[Name]" value="Something">   
  <input type="text" name="Contact[Email]" value="Else">
  <textarea name="Contact[Message]">For this message</textarea>
  <button type="submit">Submit</button>
</form>
In PHP I would simple use this to get the data:
<?php 
   print_r($_POST["Contact"])
?>
// Output would be something like this:
Array
(
    [Name] => Something
    [Email] => Else
    [Message] => For this message
)
BUT in go... either I get one by one or the whole thing but not the Contact[] Array only such as PHP
I thought about 2 solutions:
1) Get one by one:
// r := *http.Request
err := r.ParseForm()
if err != nil {
    w.Write([]byte(err.Error()))
    return
}
contact := make(map[string]string)
contact["Name"] = r.PostFormValue("Contact[Name]")
contact["Email"] = r.PostFormValue("Contact[Email]")
contact["Message"] = r.PostFormValue("Contact[Message]")
fmt.Println(contact)
// Output
map[Name:Something Email:Else Message:For this Message]
Note that the map keys are the whole: "Contact[Name]"...
2) Range whole map r.Form and "parse|obtain" those values with Prefix 
"Contact[" and then replacing "Contact[" and "]" with empty string 
so I can get the Form array Key only such the PHP Example
I went for this work around by my own but... ranging over the whole form may not be a good idea (?)
// ContactPost process the form sent by the user
func ContactPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    err := r.ParseForm()
    if err != nil {
        w.Write([]byte(err.Error()))
        return
    }
    contact := make(map[string]string)
   for i := range r.Form {
       if strings.HasPrefix(i, "Contact[") {
           rp := strings.NewReplacer("Contact[", "", "]", "")
           contact[rp.Replace(i)] = r.Form.Get(i)
       }
   }
    w.Write([]byte(fmt.Sprint(contact)))
}
//Output
map[Name:Something Email:Else Message:For this Message]
Both solutions give me the same output... But in the 2nd example I don't necessarily need to know the keys of "Contact[]"
I know... I may just forget about that "Form Array" and use name="Email" on my inputs and retrieve one by one but... I've passing through some scenarios where I use ONE form that contain more than 2 arrays of data and do different things with each one, like ORMs
Question 1: Is there a easier way to get my Form Array as an actual map in Golang like PHP does?
Question 2: 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.
Sorry for my bad English... Thanks in advance!
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.
I had the same question. The submission of array form params is also idiomatic in the Ruby/Rails world where I'm coming from. But, after some research, it looks like this is not really the "Go-way".
I've been using the dot prefix convention: contact.name, contact.email, etc.
func parseFormHandler(writer http.ResponseWriter, request *http.Request) {
    request.ParseForm()
    userParams := make(map[string]string)
    for key, _ := range request.Form {
        if strings.HasPrefix(key, "contact.") {
            userParams[string(key[8:])] = request.Form.Get(key)
        }
    }
    fmt.Fprintf(writer, "%#v\n", userParams)
}
func main() {
    server := http.Server{Addr: ":8088"}
    http.HandleFunc("/", parseFormHandler)
    server.ListenAndServe()
}
Running this server and then curling it:
$ curl -id "contact.name=Jeffrey%20Lebowski&[email protected]&contact.message=I%20hate%20the%20Eagles,%20man." http://localhost:8088
Results in:
HTTP/1.1 200 OK
Date: Thu, 12 May 2016 16:41:44 GMT
Content-Length: 113
Content-Type: text/plain; charset=utf-8
map[string]string{"name":"Jeffrey Lebowski", "email":"[email protected]", "message":"I hate the Eagles, man."}
You can also use the Gorilla Toolkit's Schema Package to parse the form params into a struct, like so:
type Submission struct {
    Contact Contact
}
type Contact struct {
    Name    string
    Email   string
    Message string
}
func parseFormHandler(writer http.ResponseWriter, request *http.Request) {
    request.ParseForm()
    decoder := schema.NewDecoder()
    submission := new(Submission)
    err := decoder.Decode(submission, request.Form)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Fprintf(writer, "%#v\n", submission)
}
Running this server and then curling it:
$ curl -id "Contact.Name=Jeffrey%20Lebowski&[email protected]&Contact.Message=I%20hate%20the%20Eagles,%20man." http://localhost:8088
Results in:
HTTP/1.1 200 OK
Date: Thu, 12 May 2016 17:03:38 GMT
Content-Length: 128
Content-Type: text/plain; charset=utf-8
&main.Submission{Contact:main.Contact{Name:"Jeffrey Lebowski", Email:"[email protected]", Message:"I hate the Eagles, man."}}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With