I develop some server in golang. I try to create some wrapper-function, which can helps me in future.
What I have:
1) I had some DTO structs, for example:
type Request struct {
Field1 string `json:"field1"`
Field2 string `json:"field2"`
}
type Response struct {
Field1 string `json:"field1"`
Field2 string `json:"field2"`
Field3 string `json:"field3"`
}
2) I had some functions, in controller layer, which (by conventions) receives 1 argument (pointer to struct) and returns 1 result (pointer to struct), for example:
func SomeHandler(request *Request) *Response{
...do something
return &Response{"first","second","third"}
}
What I need:
I need to write wrapper function which receives as argument:
This wrapper function must:
Wrapper must work correct with any types of 'controller' functions - signatures of this functions is different (different argument type, different result type)
Can anybody help me with implementing of this wrapper?
What you're doing is a bit weird but reflect
can provide all the info you need.
func myFunction(a string, b int32) error {
return nil
}
func myWrapper(mystery interface{}) {
typ := reflect.TypeOf(mystery)
// Check typ.Kind before playing with In(i);
for i := 0; i < typ.NumIn(); i++ {
fmt.Printf("Param %d: %v
", i, typ.In(i))
}
for i := 0; i < typ.NumOut(); i++ {
fmt.Printf("Result %d: %v
", i, typ.Out(i))
}
}
This prints:
Param 0: string
Param 1: int32
Result 0: error
Something like this should work (untested):
func wrapper(ctlr interface{}, w http.ResponseWriter, r *http.Request) error {
tpe := reflect.TypeOf(ctlr)
if tpe.Kind() != reflect.Func || tpe.NumIn() != 1 || tpe.NumOut() != 1 {
// TODO: handle wrong ctlr type
}
// 1. Determine type of argument of 'controller' function
argt := tpe.In(0)
// 2. Determine type of result of 'controller' function
// rest := tpe.Out(0) // commented out since it's useless
// 3. Instantiate and fill argument value from Body of *http.Request (decode from json)
arg := reflect.Zero(argt)
err := json.NewDecoder(r.Body).Decode(&arg)
if err != nil {
// TODO: handle err
}
// 4. Call controller Function with instantiated on previous step argument
resv := reflect.ValueOf(ctlr).Call([]reflect.Value{arg})[0]
// 5. Write results of previous step into http.ResponseWriter (encoded as json)
err = json.NewEncoder(w).Encode(resv.Interface())
if err != nil {
// TODO: handle err
}
return nil
}
Note that the second step is unnecessary.