error.go raw

   1  // Copyright 2016 Qiang Xue. All rights reserved.
   2  // Use of this source code is governed by a MIT-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package validation
   6  
   7  import (
   8  	"bytes"
   9  	"encoding/json"
  10  	"fmt"
  11  	"sort"
  12  	"strings"
  13  	"text/template"
  14  )
  15  
  16  type (
  17  	// Error interface represents an validation error
  18  	Error interface {
  19  		Error() string
  20  		Code() string
  21  		Message() string
  22  		SetMessage(string) Error
  23  		Params() map[string]interface{}
  24  		SetParams(map[string]interface{}) Error
  25  	}
  26  
  27  	// ErrorObject is the default validation error
  28  	// that implements the Error interface.
  29  	ErrorObject struct {
  30  		code    string
  31  		message string
  32  		params  map[string]interface{}
  33  	}
  34  
  35  	// Errors represents the validation errors that are indexed by struct field names, map or slice keys.
  36  	// values are Error or Errors (for map, slice and array error value is Errors).
  37  	Errors map[string]error
  38  
  39  	// InternalError represents an error that should NOT be treated as a validation error.
  40  	InternalError interface {
  41  		error
  42  		InternalError() error
  43  	}
  44  
  45  	internalError struct {
  46  		error
  47  	}
  48  )
  49  
  50  // NewInternalError wraps a given error into an InternalError.
  51  func NewInternalError(err error) InternalError {
  52  	return internalError{error: err}
  53  }
  54  
  55  // InternalError returns the actual error that it wraps around.
  56  func (e internalError) InternalError() error {
  57  	return e.error
  58  }
  59  
  60  // SetCode set the error's translation code.
  61  func (e ErrorObject) SetCode(code string) Error {
  62  	e.code = code
  63  	return e
  64  }
  65  
  66  // Code get the error's translation code.
  67  func (e ErrorObject) Code() string {
  68  	return e.code
  69  }
  70  
  71  // SetParams set the error's params.
  72  func (e ErrorObject) SetParams(params map[string]interface{}) Error {
  73  	e.params = params
  74  	return e
  75  }
  76  
  77  // AddParam add parameter to the error's parameters.
  78  func (e ErrorObject) AddParam(name string, value interface{}) Error {
  79  	if e.params == nil {
  80  		e.params = make(map[string]interface{})
  81  	}
  82  
  83  	e.params[name] = value
  84  	return e
  85  }
  86  
  87  // Params returns the error's params.
  88  func (e ErrorObject) Params() map[string]interface{} {
  89  	return e.params
  90  }
  91  
  92  // SetMessage set the error's message.
  93  func (e ErrorObject) SetMessage(message string) Error {
  94  	e.message = message
  95  	return e
  96  }
  97  
  98  // Message return the error's message.
  99  func (e ErrorObject) Message() string {
 100  	return e.message
 101  }
 102  
 103  // Error returns the error message.
 104  func (e ErrorObject) Error() string {
 105  	if len(e.params) == 0 {
 106  		return e.message
 107  	}
 108  
 109  	res := bytes.Buffer{}
 110  	_ = template.Must(template.New("err").Parse(e.message)).Execute(&res, e.params)
 111  
 112  	return res.String()
 113  }
 114  
 115  // Error returns the error string of Errors.
 116  func (es Errors) Error() string {
 117  	if len(es) == 0 {
 118  		return ""
 119  	}
 120  
 121  	keys := make([]string, len(es))
 122  	i := 0
 123  	for key := range es {
 124  		keys[i] = key
 125  		i++
 126  	}
 127  	sort.Strings(keys)
 128  
 129  	var s strings.Builder
 130  	for i, key := range keys {
 131  		if i > 0 {
 132  			s.WriteString("; ")
 133  		}
 134  		if errs, ok := es[key].(Errors); ok {
 135  			_, _ = fmt.Fprintf(&s, "%v: (%v)", key, errs)
 136  		} else {
 137  			_, _ = fmt.Fprintf(&s, "%v: %v", key, es[key].Error())
 138  		}
 139  	}
 140  	s.WriteString(".")
 141  	return s.String()
 142  }
 143  
 144  // MarshalJSON converts the Errors into a valid JSON.
 145  func (es Errors) MarshalJSON() ([]byte, error) {
 146  	errs := map[string]interface{}{}
 147  	for key, err := range es {
 148  		if ms, ok := err.(json.Marshaler); ok {
 149  			errs[key] = ms
 150  		} else {
 151  			errs[key] = err.Error()
 152  		}
 153  	}
 154  	return json.Marshal(errs)
 155  }
 156  
 157  // Filter removes all nils from Errors and returns back the updated Errors as an error.
 158  // If the length of Errors becomes 0, it will return nil.
 159  func (es Errors) Filter() error {
 160  	for key, value := range es {
 161  		if value == nil {
 162  			delete(es, key)
 163  		}
 164  	}
 165  	if len(es) == 0 {
 166  		return nil
 167  	}
 168  	return es
 169  }
 170  
 171  // NewError create new validation error.
 172  func NewError(code, message string) Error {
 173  	return ErrorObject{
 174  		code:    code,
 175  		message: message,
 176  	}
 177  }
 178  
 179  // Assert that our ErrorObject implements the Error interface.
 180  var _ Error = ErrorObject{}
 181