github.com/profzone/eden-framework@v1.0.10/pkg/courier/transport_http/transform/parameter_meta.go (about)

     1  package transform
     2  
     3  import (
     4  	"encoding"
     5  	"encoding/json"
     6  	"io"
     7  	"io/ioutil"
     8  	"reflect"
     9  
    10  	"github.com/profzone/eden-framework/pkg/courier/status_error"
    11  	"github.com/profzone/eden-framework/pkg/reflectx"
    12  	"github.com/profzone/eden-framework/pkg/strings"
    13  )
    14  
    15  func NewParameterMeta(field *reflect.StructField, rv reflect.Value, tagIn string, tagInFlags TagFlags) *ParameterMeta {
    16  	name, nameFlags := GetParameterDisplayName(field)
    17  
    18  	p := &ParameterMeta{
    19  		Name:    name,
    20  		In:      tagIn,
    21  		InFlags: tagInFlags,
    22  		Field:   field,
    23  		Value:   rv,
    24  	}
    25  
    26  	style, _, styleFlags := GetTagStyle(field)
    27  	p.Style = style
    28  	p.StyleFlags = styleFlags
    29  
    30  	if p.Style == "" {
    31  		switch p.In {
    32  		case "query", "cookie":
    33  			p.Style = "form"
    34  			// todo set explode as default
    35  		case "path", "header":
    36  			p.Style = "simple"
    37  		}
    38  	}
    39  
    40  	p.Format, _, _ = GetTagFmt(field)
    41  	if p.Format == "" {
    42  		p.Format = "json"
    43  	}
    44  
    45  	defaultValue, hasDefaultTag := GetTagDefault(field)
    46  	p.DefaultValue = defaultValue
    47  
    48  	p.Required = true
    49  	if hasOmitempty, ok := nameFlags["omitempty"]; ok {
    50  		p.Required = !hasOmitempty
    51  	} else {
    52  		// todo don't use non-default as required
    53  		p.Required = !hasDefaultTag
    54  	}
    55  
    56  	tagValidate, _ := GetTagValidate(field)
    57  	p.TagValidate = tagValidate
    58  
    59  	tagErrMsg, _ := GetTagErrMsg(field)
    60  	p.TagErrMsg = tagErrMsg
    61  
    62  	return p
    63  }
    64  
    65  type ParameterMeta struct {
    66  	Name   string
    67  	In     string
    68  	Format string
    69  
    70  	InFlags TagFlags
    71  	Field   *reflect.StructField
    72  	Value   reflect.Value
    73  
    74  	Style      string
    75  	StyleFlags TagFlags
    76  
    77  	DefaultValue string
    78  	Required     bool
    79  
    80  	TagValidate string
    81  	TagErrMsg   string
    82  }
    83  
    84  func (p *ParameterMeta) IsExplode() bool {
    85  	return p.StyleFlags != nil && p.StyleFlags["explode"]
    86  }
    87  
    88  func (p *ParameterMeta) IsMultipart() bool {
    89  	return p.InFlags != nil && p.InFlags["multipart"]
    90  }
    91  
    92  // for parameter
    93  func (p *ParameterMeta) UnmarshalStringAndValidate(ss ...string) error {
    94  	return p.UnmarshalAndValidate(BytesList(ResolveCommaSplitValues(p.Field.Type, ss...)...)...)
    95  }
    96  
    97  func (p *ParameterMeta) UnmarshalAndValidate(dataList ...[]byte) error {
    98  	if err := p.Unmarshal(dataList...); err != nil {
    99  		if statusErr, ok := err.(*status_error.StatusError); ok {
   100  			return statusErr
   101  		}
   102  		return status_error.InvalidField.StatusError().WithErrorField(p.In, p.Name, err.Error())
   103  	}
   104  	if valid, errFields := p.Validate(); !valid {
   105  		return status_error.InvalidField.StatusError().WithErrorFields(errFields...)
   106  	}
   107  	return nil
   108  }
   109  
   110  // for body
   111  func (p *ParameterMeta) UnmarshalFromReader(reader io.Reader) error {
   112  	if reader == nil {
   113  		return status_error.ReadFailed.StatusError()
   114  	}
   115  	data, readErr := ioutil.ReadAll(reader)
   116  	if readErr != nil {
   117  		return status_error.ReadFailed.StatusError()
   118  	}
   119  	if len(data) == 0 {
   120  		return status_error.InvalidBodyStruct.StatusError().WithDesc("empty body")
   121  	}
   122  	return p.UnmarshalAndValidate(data)
   123  }
   124  
   125  func (p *ParameterMeta) Unmarshal(datalist ...[]byte) error {
   126  	return ContentUnmarshal(p.Value, p.Field.Type, p.In, p.Name, p.Format, datalist...)
   127  }
   128  
   129  func (p *ParameterMeta) Marshal() (dataList [][]byte, err error) {
   130  	return ContentMarshal(p.Value, p.In, p.Format)
   131  }
   132  
   133  var rtypeEncodingTextMarshaler = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
   134  
   135  func (p *ParameterMeta) Validate() (bool, status_error.ErrorFields) {
   136  	errMsgMap := ErrMsgMap{}
   137  	parentField := ""
   138  
   139  	typ := reflectx.IndirectType(p.Field.Type)
   140  
   141  	kind := typ.Kind()
   142  	if (kind == reflect.Struct || kind == reflect.Slice || kind == reflect.Array) && !typ.Implements(rtypeEncodingTextMarshaler) {
   143  		validateScan := NewScanner()
   144  		isValid, errMsgs := validateScan.Validate(p.Value, p.Field.Type)
   145  		if !isValid {
   146  			errMsgMap = errMsgMap.Merge(errMsgs)
   147  		}
   148  		if p.In == "formData" {
   149  			parentField = p.Name
   150  		}
   151  	} else {
   152  		errMsg := MarshalAndValidate(
   153  			p.Value, p.Field.Type,
   154  			p.DefaultValue, p.Required,
   155  			p.TagValidate, p.TagErrMsg,
   156  		)
   157  
   158  		if errMsg != "" {
   159  			errMsgMap[p.Name] = errMsg
   160  		}
   161  	}
   162  
   163  	return len(errMsgMap) == 0, errMsgMap.ErrorFieldsIn(p.In, parentField)
   164  }
   165  
   166  func BytesList(ss ...string) (dataList [][]byte) {
   167  	for _, s := range ss {
   168  		dataList = append(dataList, []byte(s))
   169  	}
   170  	return
   171  }
   172  
   173  func ContentMarshal(rv reflect.Value, in string, format string) (dataList [][]byte, err error) {
   174  	if rv.Kind() == reflect.Ptr && rv.IsNil() {
   175  		return
   176  	}
   177  
   178  	rv = reflect.Indirect(rv)
   179  
   180  	if marshal, ok := rv.Interface().(encoding.TextMarshaler); ok {
   181  		data, marshalErr := marshal.MarshalText()
   182  		if marshalErr != nil {
   183  			err = marshalErr
   184  			return
   185  		}
   186  		dataList = [][]byte{data}
   187  		return
   188  	}
   189  
   190  	switch rv.Kind() {
   191  	case reflect.Map, reflect.Struct:
   192  		data, errForMarshal := GetContentTransformer(format).Marshal(rv.Interface())
   193  		if errForMarshal != nil {
   194  			err = errForMarshal
   195  			return
   196  		}
   197  		dataList = [][]byte{data}
   198  		return
   199  	case reflect.Slice, reflect.Array:
   200  		if data, ok := rv.Interface().([]byte); ok {
   201  			dataList = [][]byte{data}
   202  			return
   203  		}
   204  		if in == "body" {
   205  			data, errForMarshal := GetContentTransformer(format).Marshal(rv.Interface())
   206  			if errForMarshal != nil {
   207  				err = errForMarshal
   208  				return
   209  			}
   210  			dataList = [][]byte{data}
   211  			return
   212  		}
   213  		for i := 0; i < rv.Len(); i++ {
   214  			itemsList, errForStringify := ContentMarshal(rv.Index(i), in, format)
   215  			if errForStringify != nil {
   216  				err = errForStringify
   217  				return
   218  			}
   219  			dataList = append(dataList, itemsList...)
   220  		}
   221  		return
   222  	default:
   223  		data, errForStringify := Stringify(rv.Interface())
   224  		if errForStringify != nil {
   225  			err = errForStringify
   226  			return
   227  		}
   228  		dataList = [][]byte{data}
   229  		return
   230  	}
   231  }
   232  
   233  func ContentUnmarshal(rv reflect.Value, tpe reflect.Type, in string, name string, format string, dataList ...[]byte) error {
   234  	if len(dataList) == 0 || len(dataList[0]) == 0 {
   235  		return nil
   236  	}
   237  
   238  	if rv.Kind() == reflect.Ptr && rv.IsNil() && rv.CanSet() {
   239  		rv.Set(reflect.New(reflectx.IndirectType(tpe)))
   240  	}
   241  
   242  	rv = reflect.Indirect(rv)
   243  
   244  	if textUnmarshaler, ok := rv.Addr().Interface().(encoding.TextUnmarshaler); ok {
   245  		if err := textUnmarshaler.UnmarshalText(dataList[0]); err != nil {
   246  			return err
   247  		}
   248  		return nil
   249  	}
   250  
   251  	switch rv.Kind() {
   252  	case reflect.Map, reflect.Struct:
   253  		if rv.CanAddr() {
   254  			rv = rv.Addr()
   255  		}
   256  		return structUnmarshal(in, name, format, dataList[0], rv.Interface())
   257  	case reflect.Slice:
   258  		if _, ok := rv.Interface().([]byte); ok {
   259  			rv.SetBytes(dataList[0])
   260  			return nil
   261  		}
   262  
   263  		if in == "body" {
   264  			if rv.CanAddr() {
   265  				rv = rv.Addr()
   266  			}
   267  			return structUnmarshal(in, name, format, dataList[0], rv.Interface())
   268  		}
   269  
   270  		sliceRv := reflect.MakeSlice(tpe, len(dataList), cap(dataList))
   271  
   272  		itemType := rv.Type().Elem()
   273  		for i, data := range dataList {
   274  			err := ContentUnmarshal(sliceRv.Index(i), itemType, in, name, format, data)
   275  			if err != nil {
   276  				return err
   277  			}
   278  		}
   279  
   280  		rv.Set(sliceRv)
   281  
   282  		return nil
   283  	case reflect.Array:
   284  		if in == "body" {
   285  			if rv.CanAddr() {
   286  				rv = rv.Addr()
   287  			}
   288  			return structUnmarshal(in, name, format, dataList[0], rv.Interface())
   289  		}
   290  		itemType := rv.Type().Elem()
   291  		for i, data := range dataList {
   292  			err := ContentUnmarshal(rv.Index(i), itemType, in, name, format, data)
   293  			if err != nil {
   294  				return err
   295  			}
   296  		}
   297  		return nil
   298  	default:
   299  		return str.ConvertFromStr(string(dataList[0]), rv)
   300  	}
   301  }
   302  
   303  func structUnmarshal(in string, rootField string, format string, data []byte, v interface{}) error {
   304  	err := GetContentTransformer(format).Unmarshal(data, v)
   305  	if err != nil {
   306  		statusError := status_error.InvalidBodyStruct.StatusError()
   307  		if unmarshalTypeErr, ok := err.(*json.UnmarshalTypeError); ok {
   308  			if unmarshalTypeErr.Type == nil {
   309  				return statusError.WithErrorField(in, LocateJSONPath(data, unmarshalTypeErr.Offset), unmarshalTypeErr.Value)
   310  			}
   311  			return statusError.WithErrorField(in, LocateJSONPath(data, unmarshalTypeErr.Offset), unmarshalTypeErr.Error())
   312  		}
   313  		return statusError.WithErrorField(in, rootField, "参数格式错误").WithDesc(err.Error())
   314  	}
   315  	return nil
   316  }