I have a route which works with multipart/form-data. All was good before I tried to pass nested objects via postman. There are a lot of code in this function but I removed it for this question because it does not matter.
func (h *handler) SubmitFormNewPark(w http.ResponseWriter, r *http.Request) {
ctx := context.InitFromHTTP(w, r, "submit_form_new_park")
defer ctx.OnExit(nil)
err := r.ParseMultipartForm(0)
if err != nil {
logger.Get().Warn(ctx, "can't parse new park form", zap.Error(err))
h.writeResponse(ctx, w, models.FormParkResponse{Success: false})
return
}
multipartForm := make(map[string]interface{})
for key, value := range r.MultipartForm.Value {
multipartForm[key] = value
}
}
Firstly all was good because I had not nested object
But after I added nested object there are different keys in r.MultipartForm.Value
If I print the r.MultipartForm.Value I get next map
map[city:[city] entity_name:[entity_name] ip_info[ip_address]:[ip_address] ip_info[ip_fio]:[ip_fio] name:[Name] office_address:[office address] office_phone:[74954954949]]
But I expect get "ip_info" key as map with keys ip_address and ip_fio
I also tried to use keys such as ip_info[0][ip_fio] and ip_info[0][ip_address].
You can parse nested objects with this code:
Note: You can improove this example to recursively parse nested objects in nested objects
package main
import (
"fmt"
"log"
"net/http"
"regexp"
)
var rxNestedKey = regexp.MustCompile(`^(?P<key>[A-Za-z0-9_]+)\[(?P<n_key>[A-Za-z0-9_]+)\]$`)
func Handler(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(0)
if err != nil {
return
}
multipartForm := map[string]interface{}{}
nestedBuf := map[string]map[string]interface{}{}
for key, value := range r.MultipartForm.Value {
// check key has nested key
if rxNestedKey.MatchString(key) {
// parse nested key (nK) and key (k)
k := rxNestedKey.FindStringSubmatch(key)[1]
nK := rxNestedKey.FindStringSubmatch(key)[2]
if nestedBuf[k] == nil {
nestedBuf[k] = map[string]interface{}{}
}
nestedBuf[k][nK] = value
} else {
multipartForm[key] = value
}
}
// collect all nested data from buff
for k, v := range nestedBuf {
multipartForm[k] = v
}
fmt.Printf("%+v\n", multipartForm)
}
func main() {
http.HandleFunc("/", Handler)
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
Parsed as:
map[ip:map[address:[127.0.0.1] port:[8080]] office_city:[Moscow] office_phone:[7845612349879]]