Skip to content

Instantly share code, notes, and snippets.

@tshaddix
Created September 4, 2014 19:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tshaddix/4719b13c9d74f9312cba to your computer and use it in GitHub Desktop.
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.
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