package valid import ( "bytes" "encoding/json" "errors" "fmt" "sort" "strings" "text/template" ) var ( // ErrStructPointer is the error that a struct being validated is not specified as a pointer. ErrStructPointer = errors.New("only a pointer to a struct can be validated") ) // ErrorTag is the struct tag name used to customize the error field name for a struct field. var ErrorTag = "json" // Error interface represents an validation error type Error interface { Error() string Code() string Message() string SetMessage(string) Error Params() map[string]interface{} SetParams(map[string]interface{}) Error } // InternalError represents an error that should NOT be treated as a validation error. type InternalError interface { error InternalError() error } type internalError struct { error } // NewInternalError wraps a given error into an InternalError. func NewInternalError(err error) InternalError { return internalError{error: err} } // InternalError returns the actual error that it wraps around. func (e internalError) InternalError() error { return e.error } // Errors represents the validation errors that are indexed by struct field names, map or slice keys. // values are Error or Errors (for map, slice and array error value is Errors). type Errors map[string]error // Error returns the error string of Errors. func (es Errors) Error() string { if len(es) == 0 { return "" } keys := make([]string, len(es)) i := 0 for key := range es { keys[i] = key i++ } sort.Strings(keys) var s strings.Builder for i, key := range keys { if i > 0 { s.WriteString("; ") } if errs, ok := es[key].(Errors); ok { _, _ = fmt.Fprintf(&s, "%v: (%v)", key, errs) } else { _, _ = fmt.Fprintf(&s, "%v: %v", key, es[key].Error()) } } s.WriteString(".") return s.String() } // MarshalJSON converts the Errors into a valid JSON. func (es Errors) MarshalJSON() ([]byte, error) { errs := map[string]interface{}{} for key, err := range es { if ms, ok := err.(json.Marshaler); ok { errs[key] = ms } else { errs[key] = err.Error() } } return json.Marshal(errs) } // Filter removes all nils from Errors and returns back the updated Errors as an error. // If the length of Errors becomes 0, it will return nil. func (es Errors) Filter() error { for key, value := range es { if value == nil { delete(es, key) } } if len(es) == 0 { return nil } return es } // NewError create new validation error. func NewError(code, message string) Error { return ErrorObject{ code: code, message: message, } } // Assert that our ErrorObject implements the Error interface. var _ Error = ErrorObject{} // ErrorObject is the default validation error // that implements the Error interface. type ErrorObject struct { code string message string params map[string]interface{} } // SetCode set the error's translation code. func (e ErrorObject) SetCode(code string) Error { e.code = code return e } // Code get the error's translation code. func (e ErrorObject) Code() string { return e.code } // SetParams set the error's params. func (e ErrorObject) SetParams(params map[string]interface{}) Error { e.params = params return e } // AddParam add parameter to the error's parameters. func (e ErrorObject) AddParam(name string, value interface{}) Error { if e.params == nil { e.params = make(map[string]interface{}) } e.params[name] = value return e } // Params returns the error's params. func (e ErrorObject) Params() map[string]interface{} { return e.params } // SetMessage set the error's message. func (e ErrorObject) SetMessage(message string) Error { e.message = message return e } // Message return the error's message. func (e ErrorObject) Message() string { return e.message } // Error returns the error message. func (e ErrorObject) Error() string { if len(e.params) == 0 { return e.message } res := bytes.Buffer{} _ = template.Must(template.New("err").Parse(e.message)).Execute(&res, e.params) return res.String() } // ErrFieldPointer is the error that a field is not specified as a pointer. type ErrFieldPointer int // Error returns the error string of ErrFieldPointer. func (e ErrFieldPointer) Error() string { return fmt.Sprintf("field #%v must be specified as a pointer", int(e)) } // ErrFieldNotFound is the error that a field cannot be found in the struct. type ErrFieldNotFound int // Error returns the error string of ErrFieldNotFound. func (e ErrFieldNotFound) Error() string { return fmt.Sprintf("field #%v cannot be found in the struct", int(e)) }