Go – in golang, general function to load http form data into a struct

go

In Go, http form data (e.g. from a POST or PUT request) can be accessed as a map of the form map[string][]string. I'm having a hard time converting this to structs in a generalizable way.

For example, I want to load a map like:

m := map[string][]string {
    "Age": []string{"20"},
    "Name": []string{"John Smith"},
}

Into a model like:

type Person struct {
    Age   int
    Name string
}

So I'm trying to write a function with the signature LoadModel(obj interface{}, m map[string][]string) []error that will load the form data into an interface{} that I can type cast back to a Person. Using reflection so that I can use it on any struct type with any fields, not just a Person, and so that I can convert the string from the http data to an int, boolean, etc as necessary.

Using the answer to this question in golang, using reflect, how do you set the value of a struct field? I can set the value of a person using reflect, e.g.:

p := Person{25, "John"}
reflect.ValueOf(&p).Elem().Field(1).SetString("Dave")

But then I'd have to copy the load function for every type of struct I have. When I try it for an interface{} it doesn't work.

pi := (interface{})(p)
reflect.ValueOf(&pi).Elem().Field(1).SetString("Dave")
// panic: reflect: call of reflect.Value.Field on interface Value

How can I do this in the general case? Or even better, is there a more idiomatic Go way to accomplish what I'm trying to do?

Best Answer

You need to make switches for the general case, and load the different field types accordingly. This is basic part.

It gets harder when you have slices in the struct (then you have to load them up to the number of elements in the form field), or you have nested structs.

I have written a package that does this. Please see:

http://www.gorillatoolkit.org/pkg/schema

Related Topic