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