diff options
author | Alexander NeonXP Kiryukhin <i@neonxp.ru> | 2024-07-29 02:38:17 +0300 |
---|---|---|
committer | Alexander NeonXP Kiryukhin <i@neonxp.ru> | 2024-07-29 02:38:17 +0300 |
commit | 2916082d5ed94ef86ad58bdb7256ae07b214c4f3 (patch) | |
tree | 322a0e9172c07457a892f9737839843b8c584864 /binder.go |
Начальный коммит
Diffstat (limited to 'binder.go')
-rw-r--r-- | binder.go | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/binder.go b/binder.go new file mode 100644 index 0000000..f618a1a --- /dev/null +++ b/binder.go @@ -0,0 +1,88 @@ +package mux + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + "reflect" + "strconv" + "strings" +) + +func Bind[T any](r *http.Request, obj *T) error { + contentType := r.Header.Get("Content-Type") + switch { + case strings.HasPrefix(contentType, "multipart/form-data"), + strings.HasPrefix(contentType, "application/x-www-form-urlencoded"): + if err := r.ParseForm(); err != nil { + return err + } + return bindForm(r.Form, obj) + case strings.HasPrefix(contentType, "application/json"): + defer r.Body.Close() + return json.NewDecoder(r.Body).Decode(obj) + case r.Method == http.MethodGet: + return bindForm(r.URL.Query(), obj) + case r.Method == http.MethodPost: + return fmt.Errorf("invalid content-type: %s", contentType) + } + + return nil +} + +func bindForm(values url.Values, obj any) error { + val := reflect.ValueOf(obj) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + + fields := val.NumField() + + for i := 0; i < fields; i++ { + f := val.Field(i) + if !f.IsValid() { + continue + } + if !f.CanSet() { + continue + } + t := val.Type().Field(i) + k := t.Tag.Get("form") + if k == "" { + continue + } + if !values.Has(k) { + continue + } + v := values.Get(k) + + switch f.Type().Kind() { + case reflect.Bool: + switch v { + case "on", "true", "1": + f.SetBool(true) + default: + f.SetBool(false) + } + case reflect.Int, reflect.Int64: + if i, e := strconv.ParseInt(v, 0, 0); e == nil { + f.SetInt(i) + } else { + return fmt.Errorf("could not set int value of %s: %s", k, e) + } + case reflect.Float64: + if fl, e := strconv.ParseFloat(v, 64); e == nil { + f.SetFloat(fl) + } else { + return fmt.Errorf("could not set float64 value of %s: %s", k, e) + } + case reflect.String: + f.SetString(v) + default: + return fmt.Errorf("unsupported format %v for field %s", f.Type().Kind(), k) + } + } + + return nil +} |