apigen/test/demo/api/apigen.go

203 lines
3.9 KiB
Go

package api
import (
"context"
"encoding/json"
"errors"
"net/http"
"reflect"
"strconv"
"strings"
)
func handleTag(s string, r *http.Request) string {
parts := strings.Split(s, ":")
where := "Q"
key := ""
if len(parts) == 1 {
key = parts[0]
} else {
where = parts[0]
key = parts[1]
}
switch where {
case "Q":
return r.URL.Query().Get(key)
case "H":
return r.Header.Get(key)
case "P":
switch key {
case "*":
return r.URL.Path
case "last":
pps := strings.Split(r.URL.Path, "/")
return pps[len(pps)-1]
case "len":
pps := strings.Split(r.URL.Path, "/")
return strconv.Itoa(len(pps))
default:
pps := strings.Split(r.URL.Path, "/")
n, _ := strconv.Atoi(key)
if n < len(pps) {
return pps[n]
}
return ""
}
}
return ""
}
func convert(s string, tpname string) interface{} {
switch tpname {
case "string":
return s
case "int":
v, _ := strconv.Atoi(s)
return v
case "int8":
v, _ := strconv.Atoi(s)
return int8(v)
case "int16":
v, _ := strconv.Atoi(s)
return int16(v)
case "int32":
v, _ := strconv.Atoi(s)
return int32(v)
case "int64":
v, _ := strconv.Atoi(s)
return int64(v)
case "uint":
v, _ := strconv.Atoi(s)
return uint(v)
case "float32":
v, _ := strconv.Atoi(s)
return float32(v)
case "float64":
v, _ := strconv.Atoi(s)
return float64(v)
case "bool":
return s == "true" || s == "1" || s == "Y"
}
return nil
}
func Map(r *http.Request, in interface{}) error {
tp := reflect.TypeOf(in)
vl := reflect.ValueOf(in)
if tp.Kind() == reflect.Ptr {
tp = tp.Elem()
vl = vl.Elem()
}
if tp.Kind() != reflect.Struct {
return errors.New("Type is not struct")
}
for i := 0; i < tp.NumField(); i++ {
k, ok := tp.Field(i).Tag.Lookup("in")
if ok {
str := handleTag(k, r)
v := convert(str, tp.Field(i).Type.Name())
strv := reflect.ValueOf(v)
vl.Field(i).Set(strv)
}
}
return nil
}
type API struct {
Mux *http.ServeMux
Perms map[string]string
}
func (a *API) GetPerm(r *http.Request) string {
return a.Perms[r.Method+"_"+strings.Split(r.RequestURI, "?")[0]]
}
func h_Dosome(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = context.WithValue(r.Context(), "REQ", r)
ctx = context.WithValue(ctx, "RES", w)
req := &SomeReq{}
err := Map(r, req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
if r.Method != http.MethodGet && r.Method != http.MethodHead {
err := json.NewDecoder(r.Body).Decode(req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
}
res, err := Dosome(ctx, req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Add("Content-Type", "Application/json")
err = json.NewEncoder(w).Encode(res)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
}
func h_Dosome2(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = context.WithValue(r.Context(), "REQ", r)
ctx = context.WithValue(ctx, "RES", w)
req := &SomeReq2{}
err := Map(r, req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
if r.Method != http.MethodGet && r.Method != http.MethodHead {
err := json.NewDecoder(r.Body).Decode(req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
}
res, err := Dosome2(ctx, req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Add("Content-Type", "Application/json")
err = json.NewEncoder(w).Encode(res)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
}
func Init() *API {
mux := &http.ServeMux{}
ret := &API{
Mux: mux,
Perms: make(map[string]string),
}
mux.HandleFunc("/some", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST":
h_Dosome(w, r)
default:
http.Error(w, "Method not allowed", 500)
}
})
mux.HandleFunc("/some2", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST":
h_Dosome2(w, r)
default:
http.Error(w, "Method not allowed", 500)
}
})
return ret
}