From c95d3bdfda8e4cf6c1e3c5dacdc082b119d2e603 Mon Sep 17 00:00:00 2001 From: bughou Date: Fri, 10 Jul 2020 12:23:49 +0800 Subject: [PATCH] convert resp complete --- convert-req.go | 12 +++---- convert-resp.go | 38 +++++++++++++++++++- convert.go | 28 +++++++-------- converters/header.go | 65 +++++++++++++++++++++++++++++++++++ converters/query.go | 32 +++++++++++++++++ converters/query_or_header.go | 32 ----------------- 6 files changed, 152 insertions(+), 55 deletions(-) create mode 100644 converters/header.go create mode 100644 converters/query.go delete mode 100644 converters/query_or_header.go diff --git a/convert-req.go b/convert-req.go index 62d9032..fc97ee0 100644 --- a/convert-req.go +++ b/convert-req.go @@ -47,10 +47,10 @@ func getReqFieldsConvertFuncs(typ reflect.Type, path string) (funcs []convertFun funcs = append(funcs, newParamConvertFunc(f.Type, f.Index, path)) case "Query": funcs = append(funcs, newQueryConvertFunc(f.Type, f.Index)) - case "Header": - funcs = append(funcs, newHeaderConvertFunc(f.Type, f.Index)) case "Body": funcs = append(funcs, newBodyConvertFunc(f.Type, f.Index)) + case "Header": + funcs = append(funcs, newHeaderConvertFunc(f.Type, f.Index)) case "Session": funcs = append(funcs, newSessionConvertFunc(f.Type, f.Index)) case "Ctx": @@ -71,16 +71,16 @@ func newParamConvertFunc(typ reflect.Type, index []int, path string) convertFunc } func newQueryConvertFunc(typ reflect.Type, index []int) convertFunc { - converters.ValidateQueryOrHeader(typ, `Query`) + converters.ValidateQuery(typ) return func(req reflect.Value, ctx *Context) error { - return converters.ConvertQueryOrHeader(req.FieldByIndex(index), ctx.Request.URL.Query()) + return converters.ConvertQuery(req.FieldByIndex(index), ctx.Request.URL.Query()) } } func newHeaderConvertFunc(typ reflect.Type, index []int) convertFunc { - converters.ValidateQueryOrHeader(typ, `Header`) + converters.ValidateHeader(typ) return func(req reflect.Value, ctx *Context) error { - return converters.ConvertQueryOrHeader(req.FieldByIndex(index), ctx.Request.Header) + return converters.ConvertHeader(req.FieldByIndex(index), ctx.Request.Header) } } diff --git a/convert-resp.go b/convert-resp.go index 129774b..52be912 100644 --- a/convert-resp.go +++ b/convert-resp.go @@ -3,8 +3,12 @@ package goa import ( "log" "reflect" + + "github.com/lovego/goa/converters" ) +var errorType = reflect.TypeOf((*error)(nil)).Elem() + func newRespWriteFunc(typ reflect.Type) (reflect.Type, func(*Context, reflect.Value)) { if typ.Kind() != reflect.Ptr { log.Panic("resp parameter of handler func must be a struct pointer.") @@ -13,5 +17,37 @@ func newRespWriteFunc(typ reflect.Type) (reflect.Type, func(*Context, reflect.Va if typ.Kind() != reflect.Struct { log.Panic("resp parameter of handler func must be a struct pointer.") } - return typ, nil + + for i := 0; i < typ.NumField(); i++ { + f := typ.Field(i) + switch f.Name { + case "Data": + // data can be of any type + case "Error": + if !f.Type.Implements(errorType) { + log.Panicf(`resp.Error must be of "error" type.`) + } + case "Header": + converters.ValidateRespHeader(typ) + default: + log.Panicf("Unknow field: resp.%s.", f.Name) + } + } + return typ, func(ctx *Context, resp reflect.Value) { + var data interface{} + var err error + + for i := 0; i < typ.NumField(); i++ { + f := typ.Field(i) + switch f.Name { + case "Data": + data = resp.FieldByIndex(f.Index).Interface() + case "Error": + err = resp.FieldByIndex(f.Index).Interface().(error) + case "Header": + converters.WriteRespHeader(resp.FieldByIndex(f.Index), ctx.ResponseWriter.Header()) + } + } + ctx.Data(data, err) + } } diff --git a/convert.go b/convert.go index d3d2723..02a049a 100644 --- a/convert.go +++ b/convert.go @@ -42,39 +42,35 @@ func convertHandler(h interface{}, path string) HandlerFunc { // handler example func handlerExample(req *struct { - Title string - Desc string - Params struct { + Title string + Desc string + Param struct { Id int64 } Query struct { Id int64 Page int64 } - Headers struct { - Cookie string - } Body struct { Id int64 Name string } + Header struct { + Cookie string + } Session struct { UserId int64 } Ctx *Context }, resp *struct { - Error error - Headers struct { - SetCookie string - } - Body struct { - Id int64 - Name string - } `当XXX时的返回体格式` - Body2 struct { + Data struct { Id int64 Name string - } `当YYY时的返回体格式` + } + Error error + Header struct { + SetCookie string + } }) { // resp.Body, resp.Error = users.Get(req.Params.Id) } diff --git a/converters/header.go b/converters/header.go new file mode 100644 index 0000000..818b467 --- /dev/null +++ b/converters/header.go @@ -0,0 +1,65 @@ +package converters + +import ( + "log" + "net/http" + "reflect" + + "github.com/lovego/struct_tag" + "github.com/lovego/structs" +) + +func ValidateHeader(typ reflect.Type) { + if typ.Kind() != reflect.Struct { + log.Panic("req.Header must be a struct.") + } + structs.Traverse(reflect.New(typ).Elem(), true, func(_ reflect.Value, f reflect.StructField) bool { + if !isSupportedType(f.Type) { + log.Panicf("req.Header.%s: type must be string, number or bool.", f.Name) + } + return false + }) + return +} + +func ConvertHeader(value reflect.Value, map2strs map[string][]string) (err error) { + structs.Traverse(value, true, func(v reflect.Value, f reflect.StructField) bool { + key, _ := struct_tag.Lookup(string(f.Tag), "header") + if key == "" { + key = f.Name + } + values := map2strs[key] + if len(values) > 0 && values[0] != "" { + err = Set(v, values[0]) + } + return err != nil // if err != nil, stop Traverse + }) + return +} + +func ValidateRespHeader(typ reflect.Type) { + if typ.Kind() != reflect.Struct { + log.Panic("resp.Header must be a struct.") + } + structs.Traverse(reflect.New(typ).Elem(), false, func(_ reflect.Value, f reflect.StructField) bool { + if f.Type.Kind() != reflect.String { + log.Panicf("req.Header.%s: type must be string.", f.Name) + } + return false + }) + return +} + +func WriteRespHeader(value reflect.Value, header http.Header) { + structs.Traverse(value, false, func(v reflect.Value, f reflect.StructField) bool { + if value := v.String(); value != "" { + key, _ := struct_tag.Lookup(string(f.Tag), "header") + if key == "" { + key = f.Name + } + header.Set(key, value) + } + return false + }) + return +} diff --git a/converters/query.go b/converters/query.go new file mode 100644 index 0000000..d9d863d --- /dev/null +++ b/converters/query.go @@ -0,0 +1,32 @@ +package converters + +import ( + "log" + "reflect" + + "github.com/lovego/structs" +) + +func ValidateQuery(typ reflect.Type) { + if typ.Kind() != reflect.Struct { + log.Panic("req.Query must be a struct.") + } + structs.Traverse(reflect.New(typ).Elem(), true, func(_ reflect.Value, f reflect.StructField) bool { + if !isSupportedType(f.Type) { + log.Panicf("req.Query.%s: type must be string, number or bool.", f.Name) + } + return false + }) + return +} + +func ConvertQuery(value reflect.Value, map2strs map[string][]string) (err error) { + structs.Traverse(value, true, func(v reflect.Value, f reflect.StructField) bool { + values := map2strs[lowercaseFirstLetter(f.Name)] + if len(values) > 0 && values[0] != "" { + err = Set(v, values[0]) + } + return err != nil // if err != nil, stop Traverse + }) + return +} diff --git a/converters/query_or_header.go b/converters/query_or_header.go deleted file mode 100644 index 489f32f..0000000 --- a/converters/query_or_header.go +++ /dev/null @@ -1,32 +0,0 @@ -package converters - -import ( - "log" - "reflect" - - "github.com/lovego/structs" -) - -func ValidateQueryOrHeader(typ reflect.Type, name string) { - if typ.Kind() != reflect.Struct { - log.Panicf("req.%s must be a struct.", name) - } - structs.Traverse(reflect.New(typ).Elem(), func(_ reflect.Value, f reflect.StructField) bool { - if !isSupportedType(f.Type) { - log.Panicf("req.%s.%s: type must be string, number or bool.", name, f.Name) - } - return false - }) - return -} - -func ConvertQueryOrHeader(value reflect.Value, map2strs map[string][]string) (err error) { - structs.Traverse(value, func(v reflect.Value, f reflect.StructField) bool { - values := map2strs[lowercaseFirstLetter(f.Name)] - if len(values) > 0 && values[0] != "" { - err = Set(v, values[0]) - } - return err != nil // if err != nil, stop Traverse - }) - return -}