github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/courier/status_error/status_error.go (about)

     1  package status_error
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"regexp"
     7  	"sort"
     8  	"strconv"
     9  )
    10  
    11  // code, key, msg, desc, canBeTalkError
    12  var RegexpStatusError = regexp.MustCompile(`@httpError\(([0-9]+),(.+),"(.+)?","(.+)?",(false|true)\);`)
    13  
    14  func ParseString(s string) *StatusError {
    15  	matched := RegexpStatusError.FindStringSubmatch(s)
    16  	if len(matched) != 6 {
    17  		return nil
    18  	}
    19  
    20  	code, _ := strconv.ParseInt(matched[1], 10, 64)
    21  	canBeTalkErr, _ := strconv.ParseBool(matched[5])
    22  
    23  	return &StatusError{
    24  		Code:           code,
    25  		Key:            matched[2],
    26  		Msg:            matched[3],
    27  		Desc:           matched[4],
    28  		CanBeErrorTalk: canBeTalkErr,
    29  	}
    30  }
    31  
    32  func FromError(err error) *StatusError {
    33  	if err == nil {
    34  		return nil
    35  	}
    36  
    37  	if statusErrCode, ok := err.(StatusErrorCode); ok {
    38  		return statusErrCode.StatusError()
    39  	}
    40  
    41  	if statusError, ok := err.(*StatusError); ok {
    42  		return statusError
    43  	}
    44  
    45  	return UnknownError.StatusError().WithDesc(err.Error())
    46  }
    47  
    48  func (statusErr *StatusError) String() string {
    49  	return fmt.Sprintf(`@httpError(%d,%s,"%s","%s",%v);`, statusErr.Code, statusErr.Key, statusErr.Msg, statusErr.Desc, statusErr.CanBeErrorTalk)
    50  }
    51  
    52  type StatusError struct {
    53  	// 错误 Key
    54  	Key string `json:"key" xml:"key"`
    55  	// 错误代码
    56  	Code int64 `json:"code" xml:"code"`
    57  	// 错误信息
    58  	Msg string `json:"msg" xml:"msg"`
    59  	// 详细描述
    60  	Desc string `json:"desc" xml:"desc"`
    61  	// 是否能作为错误话术
    62  	CanBeErrorTalk bool `json:"canBeTalkError" xml:"canBeTalkError"`
    63  	// 错误溯源
    64  	Source []string `json:"source" xml:"source"`
    65  	// 请求 ID
    66  	ID string `json:"id" xml:"id"`
    67  	// 出错字段
    68  	ErrorFields ErrorFields `json:"errorFields" xml:"errorFields"`
    69  }
    70  
    71  func (statusErr *StatusError) Is(err error) bool {
    72  	return FromError(statusErr).Code == statusErr.Code
    73  }
    74  
    75  func (statusErr *StatusError) Error() string {
    76  	return fmt.Sprintf("%v[%s][%d][%s%s] %s", statusErr.Source, statusErr.Key, statusErr.Code, statusErr.Msg, statusErr.ErrorFields, statusErr.Desc)
    77  }
    78  
    79  func (statusErr *StatusError) Status() int {
    80  	strCode := fmt.Sprintf("%d", statusErr.Code)
    81  	if len(strCode) < 3 {
    82  		return 0
    83  	}
    84  	status, _ := strconv.Atoi(strCode[:3])
    85  	return status
    86  }
    87  
    88  // deprecated
    89  func (statusErr *StatusError) HttpCode() int {
    90  	return statusErr.Status()
    91  }
    92  
    93  func (statusErr StatusError) WithErrTalk() *StatusError {
    94  	statusErr.CanBeErrorTalk = true
    95  	return &statusErr
    96  }
    97  
    98  func (statusErr StatusError) WithMsg(msg string) *StatusError {
    99  	statusErr.Msg = msg
   100  	return &statusErr
   101  }
   102  
   103  func (statusErr StatusError) WithoutErrTalk() *StatusError {
   104  	statusErr.CanBeErrorTalk = false
   105  	return &statusErr
   106  }
   107  
   108  func (statusErr StatusError) WithDesc(desc string) *StatusError {
   109  	statusErr.Desc = desc
   110  	return &statusErr
   111  }
   112  
   113  func (statusErr StatusError) WithID(id string) *StatusError {
   114  	statusErr.ID = id
   115  	return &statusErr
   116  }
   117  
   118  func (statusErr StatusError) WithSource(sourceName string) *StatusError {
   119  	length := len(statusErr.Source)
   120  	if length == 0 || statusErr.Source[length-1] != sourceName {
   121  		statusErr.Source = append(statusErr.Source, sourceName)
   122  	}
   123  	return &statusErr
   124  }
   125  
   126  func (statusErr StatusError) WithErrorField(in string, field string, msg string) *StatusError {
   127  	statusErr.ErrorFields = append(statusErr.ErrorFields, NewErrorField(in, field, msg))
   128  	return &statusErr
   129  }
   130  
   131  func (statusErr StatusError) WithErrorFields(errorFields ...*ErrorField) *StatusError {
   132  	statusErr.ErrorFields = append(statusErr.ErrorFields, errorFields...)
   133  	return &statusErr
   134  }
   135  
   136  func NewErrorField(in string, field string, msg string) *ErrorField {
   137  	return &ErrorField{
   138  		In:    in,
   139  		Field: field,
   140  		Msg:   msg,
   141  	}
   142  }
   143  
   144  type ErrorField struct {
   145  	// 出错字段路径
   146  	// 这个信息为一个 json 字符串,方便客户端进行定位错误原因
   147  	// 例如输入中 {"name":{ "alias" : "test"}} 中的alias出错,则返回 "name.alias"
   148  	// 如果alias是数组, 且第2个元素的a字段错误,则返回"name.alias[2].a"
   149  	Field string `json:"field" xml:"field"`
   150  	// 错误信息
   151  	Msg string `json:"msg" xml:"msg"`
   152  	// 错误字段位置
   153  	// body, query, header, path, formData
   154  	In string `json:"in" xml:"in"`
   155  }
   156  
   157  func (s ErrorField) String() string {
   158  	return "[" + s.In + "]" + s.Field + " " + s.Msg
   159  }
   160  
   161  type ErrorFields []*ErrorField
   162  
   163  func (fields ErrorFields) String() string {
   164  	if len(fields) == 0 {
   165  		return ""
   166  	}
   167  	buf := &bytes.Buffer{}
   168  	buf.WriteString("<")
   169  	for _, f := range fields {
   170  		buf.WriteString(f.String())
   171  	}
   172  	buf.WriteString(">")
   173  	return buf.String()
   174  }
   175  
   176  func (fields ErrorFields) Sort() ErrorFields {
   177  	sort.Sort(fields)
   178  	return fields
   179  }
   180  
   181  func (fields ErrorFields) Len() int {
   182  	return len(fields)
   183  }
   184  func (fields ErrorFields) Swap(i, j int) {
   185  	fields[i], fields[j] = fields[j], fields[i]
   186  }
   187  func (fields ErrorFields) Less(i, j int) bool {
   188  	return fields[i].Field < fields[j].Field
   189  }