Created
September 4, 2014 19:34
-
-
Save tshaddix/4719b13c9d74f9312cba to your computer and use it in GitHub Desktop.
Gorilla Mux param decoder for tshaddix/parcel package. Decodes params into struct fields and allows for slice population based on deliminator.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package pogs | |
import ( | |
"net/http" | |
"reflect" | |
"strings" | |
"github.com/gorilla/mux" | |
"github.com/tshaddix/parcel/encoding" | |
) | |
type ( | |
// ParamCodec is an implementation of a | |
// parcel.Decoder to parse mux params | |
ParamCodec struct { | |
deliminator string | |
} | |
// ParamTypeError is used to pass | |
// error values from the param | |
// decoding process | |
ParamTypeError struct { | |
ToType string | |
} | |
) | |
// Param returns a new param codec with the configured deliminator | |
// for slices | |
func Param(delim string) *ParamCodec { | |
return &ParamCodec{delim} | |
} | |
// Decode provides the parcel.Decoder implementation | |
func (p *ParamCodec) Decode(r *http.Request, candidate interface{}) error { | |
params := mux.Vars(r) | |
if len(params) == 0 { | |
return nil | |
} | |
// Value and type of candidate | |
value := reflect.ValueOf(candidate).Elem() | |
ty := value.Type() | |
// Iterate candidate fields | |
for i := 0; i < ty.NumField(); i++ { | |
field := ty.Field(i) | |
tag := field.Tag.Get("param") | |
// tag does not exists | |
if tag == "" { | |
continue | |
} | |
qs := params[tag] | |
// stringer value does not exist | |
if qs == "" { | |
continue | |
} | |
// value can not be set | |
if !value.Field(i).CanSet() { | |
continue | |
} | |
// Do conversion | |
kind := field.Type.Kind() | |
switch kind { | |
case reflect.Slice: | |
arr := strings.Split(qs, p.deliminator) | |
arrLen := len(arr) | |
sl := reflect.MakeSlice(field.Type, arrLen, arrLen) | |
for a, entry := range arr { | |
if err := encoding.StrSet(field.Type.Elem().Kind(), entry, sl.Index(a)); err != nil { | |
return &ParamTypeError{field.Type.Name()} | |
} | |
} | |
value.Field(i).Set(sl) | |
default: | |
if err := encoding.StrSet(kind, qs, value.Field(i)); err != nil { | |
return &ParamTypeError{field.Type.Name()} | |
} | |
} | |
} | |
return nil | |
} | |
// Error provides error implementation | |
func (e *ParamTypeError) Error() string { | |
return "ParamTypeError: Can not convert type param string to type " + e.ToType | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment