package param import ( "encoding/json" "reflect" "strconv" "strings" "time" ) type paramParser interface { parse(value string, toType reflect.Type) (interface{}, error) } func getParser(param *MethodParam, t reflect.Type) paramParser { switch t.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return intParser{} case reflect.Slice: if t.Elem().Kind() == reflect.Uint8 { //treat []byte as string return stringParser{} } if param.in == body { return jsonParser{} } elemParser := getParser(param, t.Elem()) if elemParser == (jsonParser{}) { return elemParser } return sliceParser(elemParser) case reflect.Bool: return boolParser{} case reflect.String: return stringParser{} case reflect.Float32, reflect.Float64: return floatParser{} case reflect.Ptr: elemParser := getParser(param, t.Elem()) if elemParser == (jsonParser{}) { return elemParser } return ptrParser(elemParser) default: if t.PkgPath() == "time" && t.Name() == "Time" { return timeParser{} } return jsonParser{} } } type parserFunc func(value string, toType reflect.Type) (interface{}, error) func (f parserFunc) parse(value string, toType reflect.Type) (interface{}, error) { return f(value, toType) } type boolParser struct { } func (p boolParser) parse(value string, toType reflect.Type) (interface{}, error) { return strconv.ParseBool(value) } type stringParser struct { } func (p stringParser) parse(value string, toType reflect.Type) (interface{}, error) { return value, nil } type intParser struct { } func (p intParser) parse(value string, toType reflect.Type) (interface{}, error) { return strconv.Atoi(value) } type floatParser struct { } func (p floatParser) parse(value string, toType reflect.Type) (interface{}, error) { if toType.Kind() == reflect.Float32 { res, err := strconv.ParseFloat(value, 32) if err != nil { return nil, err } return float32(res), nil } return strconv.ParseFloat(value, 64) } type timeParser struct { } func (p timeParser) parse(value string, toType reflect.Type) (result interface{}, err error) { result, err = time.Parse(time.RFC3339, value) if err != nil { result, err = time.Parse("2006-01-02", value) } return } type jsonParser struct { } func (p jsonParser) parse(value string, toType reflect.Type) (interface{}, error) { pResult := reflect.New(toType) v := pResult.Interface() err := json.Unmarshal([]byte(value), v) if err != nil { return nil, err } return pResult.Elem().Interface(), nil } func sliceParser(elemParser paramParser) paramParser { return parserFunc(func(value string, toType reflect.Type) (interface{}, error) { values := strings.Split(value, ",") result := reflect.MakeSlice(toType, 0, len(values)) elemType := toType.Elem() for _, v := range values { parsedValue, err := elemParser.parse(v, elemType) if err != nil { return nil, err } result = reflect.Append(result, reflect.ValueOf(parsedValue)) } return result.Interface(), nil }) } func ptrParser(elemParser paramParser) paramParser { return parserFunc(func(value string, toType reflect.Type) (interface{}, error) { parsedValue, err := elemParser.parse(value, toType.Elem()) if err != nil { return nil, err } newValPtr := reflect.New(toType.Elem()) newVal := reflect.Indirect(newValPtr) convertedVal, err := safeConvert(reflect.ValueOf(parsedValue), toType.Elem()) if err != nil { return nil, err } newVal.Set(convertedVal) return newValPtr.Interface(), nil }) }