1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package errors
16
17 import (
18 "encoding/json"
19 "fmt"
20 "strings"
21 )
22
23 const (
24 invalidType = "%s is an invalid type name"
25 typeFail = "%s in %s must be of type %s"
26 typeFailWithData = "%s in %s must be of type %s: %q"
27 typeFailWithError = "%s in %s must be of type %s, because: %s"
28 requiredFail = "%s in %s is required"
29 readOnlyFail = "%s in %s is readOnly"
30 tooLongMessage = "%s in %s should be at most %d chars long"
31 tooShortMessage = "%s in %s should be at least %d chars long"
32 patternFail = "%s in %s should match '%s'"
33 enumFail = "%s in %s should be one of %v"
34 multipleOfFail = "%s in %s should be a multiple of %v"
35 maxIncFail = "%s in %s should be less than or equal to %v"
36 maxExcFail = "%s in %s should be less than %v"
37 minIncFail = "%s in %s should be greater than or equal to %v"
38 minExcFail = "%s in %s should be greater than %v"
39 uniqueFail = "%s in %s shouldn't contain duplicates"
40 maxItemsFail = "%s in %s should have at most %d items"
41 minItemsFail = "%s in %s should have at least %d items"
42 typeFailNoIn = "%s must be of type %s"
43 typeFailWithDataNoIn = "%s must be of type %s: %q"
44 typeFailWithErrorNoIn = "%s must be of type %s, because: %s"
45 requiredFailNoIn = "%s is required"
46 readOnlyFailNoIn = "%s is readOnly"
47 tooLongMessageNoIn = "%s should be at most %d chars long"
48 tooShortMessageNoIn = "%s should be at least %d chars long"
49 patternFailNoIn = "%s should match '%s'"
50 enumFailNoIn = "%s should be one of %v"
51 multipleOfFailNoIn = "%s should be a multiple of %v"
52 maxIncFailNoIn = "%s should be less than or equal to %v"
53 maxExcFailNoIn = "%s should be less than %v"
54 minIncFailNoIn = "%s should be greater than or equal to %v"
55 minExcFailNoIn = "%s should be greater than %v"
56 uniqueFailNoIn = "%s shouldn't contain duplicates"
57 maxItemsFailNoIn = "%s should have at most %d items"
58 minItemsFailNoIn = "%s should have at least %d items"
59 noAdditionalItems = "%s in %s can't have additional items"
60 noAdditionalItemsNoIn = "%s can't have additional items"
61 tooFewProperties = "%s in %s should have at least %d properties"
62 tooFewPropertiesNoIn = "%s should have at least %d properties"
63 tooManyProperties = "%s in %s should have at most %d properties"
64 tooManyPropertiesNoIn = "%s should have at most %d properties"
65 unallowedProperty = "%s.%s in %s is a forbidden property"
66 unallowedPropertyNoIn = "%s.%s is a forbidden property"
67 failedAllPatternProps = "%s.%s in %s failed all pattern properties"
68 failedAllPatternPropsNoIn = "%s.%s failed all pattern properties"
69 multipleOfMustBePositive = "factor MultipleOf declared for %s must be positive: %v"
70 )
71
72
73
74 const (
75
76
77 CompositeErrorCode = 422
78
79 InvalidTypeCode = 600 + iota
80 RequiredFailCode
81 TooLongFailCode
82 TooShortFailCode
83 PatternFailCode
84 EnumFailCode
85 MultipleOfFailCode
86 MaxFailCode
87 MinFailCode
88 UniqueFailCode
89 MaxItemsFailCode
90 MinItemsFailCode
91 NoAdditionalItemsCode
92 TooFewPropertiesCode
93 TooManyPropertiesCode
94 UnallowedPropertyCode
95 FailedAllPatternPropsCode
96 MultipleOfMustBePositiveCode
97 ReadOnlyFailCode
98 )
99
100
101 type CompositeError struct {
102 Errors []error
103 code int32
104 message string
105 }
106
107
108 func (c *CompositeError) Code() int32 {
109 return c.code
110 }
111
112 func (c *CompositeError) Error() string {
113 if len(c.Errors) > 0 {
114 msgs := []string{c.message + ":"}
115 for _, e := range c.Errors {
116 msgs = append(msgs, e.Error())
117 }
118 return strings.Join(msgs, "\n")
119 }
120 return c.message
121 }
122
123 func (c *CompositeError) Unwrap() []error {
124 return c.Errors
125 }
126
127
128 func (c CompositeError) MarshalJSON() ([]byte, error) {
129 return json.Marshal(map[string]interface{}{
130 "code": c.code,
131 "message": c.message,
132 "errors": c.Errors,
133 })
134 }
135
136
137 func CompositeValidationError(errors ...error) *CompositeError {
138 return &CompositeError{
139 code: CompositeErrorCode,
140 Errors: append(make([]error, 0, len(errors)), errors...),
141 message: "validation failure list",
142 }
143 }
144
145
146 func (c *CompositeError) ValidateName(name string) *CompositeError {
147 for i, e := range c.Errors {
148 if ve, ok := e.(*Validation); ok {
149 c.Errors[i] = ve.ValidateName(name)
150 } else if ce, ok := e.(*CompositeError); ok {
151 c.Errors[i] = ce.ValidateName(name)
152 }
153 }
154
155 return c
156 }
157
158
159 func FailedAllPatternProperties(name, in, key string) *Validation {
160 msg := fmt.Sprintf(failedAllPatternProps, name, key, in)
161 if in == "" {
162 msg = fmt.Sprintf(failedAllPatternPropsNoIn, name, key)
163 }
164 return &Validation{
165 code: FailedAllPatternPropsCode,
166 Name: name,
167 In: in,
168 Value: key,
169 message: msg,
170 }
171 }
172
173
174 func PropertyNotAllowed(name, in, key string) *Validation {
175 msg := fmt.Sprintf(unallowedProperty, name, key, in)
176 if in == "" {
177 msg = fmt.Sprintf(unallowedPropertyNoIn, name, key)
178 }
179 return &Validation{
180 code: UnallowedPropertyCode,
181 Name: name,
182 In: in,
183 Value: key,
184 message: msg,
185 }
186 }
187
188
189 func TooFewProperties(name, in string, n int64) *Validation {
190 msg := fmt.Sprintf(tooFewProperties, name, in, n)
191 if in == "" {
192 msg = fmt.Sprintf(tooFewPropertiesNoIn, name, n)
193 }
194 return &Validation{
195 code: TooFewPropertiesCode,
196 Name: name,
197 In: in,
198 Value: n,
199 message: msg,
200 }
201 }
202
203
204 func TooManyProperties(name, in string, n int64) *Validation {
205 msg := fmt.Sprintf(tooManyProperties, name, in, n)
206 if in == "" {
207 msg = fmt.Sprintf(tooManyPropertiesNoIn, name, n)
208 }
209 return &Validation{
210 code: TooManyPropertiesCode,
211 Name: name,
212 In: in,
213 Value: n,
214 message: msg,
215 }
216 }
217
218
219 func AdditionalItemsNotAllowed(name, in string) *Validation {
220 msg := fmt.Sprintf(noAdditionalItems, name, in)
221 if in == "" {
222 msg = fmt.Sprintf(noAdditionalItemsNoIn, name)
223 }
224 return &Validation{
225 code: NoAdditionalItemsCode,
226 Name: name,
227 In: in,
228 message: msg,
229 }
230 }
231
232
233 func InvalidCollectionFormat(name, in, format string) *Validation {
234 return &Validation{
235 code: InvalidTypeCode,
236 Name: name,
237 In: in,
238 Value: format,
239 message: fmt.Sprintf("the collection format %q is not supported for the %s param %q", format, in, name),
240 }
241 }
242
243
244 func InvalidTypeName(typeName string) *Validation {
245 return &Validation{
246 code: InvalidTypeCode,
247 Value: typeName,
248 message: fmt.Sprintf(invalidType, typeName),
249 }
250 }
251
252
253 func InvalidType(name, in, typeName string, value interface{}) *Validation {
254 var message string
255
256 if in != "" {
257 switch value.(type) {
258 case string:
259 message = fmt.Sprintf(typeFailWithData, name, in, typeName, value)
260 case error:
261 message = fmt.Sprintf(typeFailWithError, name, in, typeName, value)
262 default:
263 message = fmt.Sprintf(typeFail, name, in, typeName)
264 }
265 } else {
266 switch value.(type) {
267 case string:
268 message = fmt.Sprintf(typeFailWithDataNoIn, name, typeName, value)
269 case error:
270 message = fmt.Sprintf(typeFailWithErrorNoIn, name, typeName, value)
271 default:
272 message = fmt.Sprintf(typeFailNoIn, name, typeName)
273 }
274 }
275
276 return &Validation{
277 code: InvalidTypeCode,
278 Name: name,
279 In: in,
280 Value: value,
281 message: message,
282 }
283
284 }
285
286
287 func DuplicateItems(name, in string) *Validation {
288 msg := fmt.Sprintf(uniqueFail, name, in)
289 if in == "" {
290 msg = fmt.Sprintf(uniqueFailNoIn, name)
291 }
292 return &Validation{
293 code: UniqueFailCode,
294 Name: name,
295 In: in,
296 message: msg,
297 }
298 }
299
300
301 func TooManyItems(name, in string, max int64, value interface{}) *Validation {
302 msg := fmt.Sprintf(maxItemsFail, name, in, max)
303 if in == "" {
304 msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
305 }
306
307 return &Validation{
308 code: MaxItemsFailCode,
309 Name: name,
310 In: in,
311 Value: value,
312 message: msg,
313 }
314 }
315
316
317 func TooFewItems(name, in string, min int64, value interface{}) *Validation {
318 msg := fmt.Sprintf(minItemsFail, name, in, min)
319 if in == "" {
320 msg = fmt.Sprintf(minItemsFailNoIn, name, min)
321 }
322 return &Validation{
323 code: MinItemsFailCode,
324 Name: name,
325 In: in,
326 Value: value,
327 message: msg,
328 }
329 }
330
331
332 func ExceedsMaximumInt(name, in string, max int64, exclusive bool, value interface{}) *Validation {
333 var message string
334 if in == "" {
335 m := maxIncFailNoIn
336 if exclusive {
337 m = maxExcFailNoIn
338 }
339 message = fmt.Sprintf(m, name, max)
340 } else {
341 m := maxIncFail
342 if exclusive {
343 m = maxExcFail
344 }
345 message = fmt.Sprintf(m, name, in, max)
346 }
347 return &Validation{
348 code: MaxFailCode,
349 Name: name,
350 In: in,
351 Value: value,
352 message: message,
353 }
354 }
355
356
357 func ExceedsMaximumUint(name, in string, max uint64, exclusive bool, value interface{}) *Validation {
358 var message string
359 if in == "" {
360 m := maxIncFailNoIn
361 if exclusive {
362 m = maxExcFailNoIn
363 }
364 message = fmt.Sprintf(m, name, max)
365 } else {
366 m := maxIncFail
367 if exclusive {
368 m = maxExcFail
369 }
370 message = fmt.Sprintf(m, name, in, max)
371 }
372 return &Validation{
373 code: MaxFailCode,
374 Name: name,
375 In: in,
376 Value: value,
377 message: message,
378 }
379 }
380
381
382 func ExceedsMaximum(name, in string, max float64, exclusive bool, value interface{}) *Validation {
383 var message string
384 if in == "" {
385 m := maxIncFailNoIn
386 if exclusive {
387 m = maxExcFailNoIn
388 }
389 message = fmt.Sprintf(m, name, max)
390 } else {
391 m := maxIncFail
392 if exclusive {
393 m = maxExcFail
394 }
395 message = fmt.Sprintf(m, name, in, max)
396 }
397 return &Validation{
398 code: MaxFailCode,
399 Name: name,
400 In: in,
401 Value: value,
402 message: message,
403 }
404 }
405
406
407 func ExceedsMinimumInt(name, in string, min int64, exclusive bool, value interface{}) *Validation {
408 var message string
409 if in == "" {
410 m := minIncFailNoIn
411 if exclusive {
412 m = minExcFailNoIn
413 }
414 message = fmt.Sprintf(m, name, min)
415 } else {
416 m := minIncFail
417 if exclusive {
418 m = minExcFail
419 }
420 message = fmt.Sprintf(m, name, in, min)
421 }
422 return &Validation{
423 code: MinFailCode,
424 Name: name,
425 In: in,
426 Value: value,
427 message: message,
428 }
429 }
430
431
432 func ExceedsMinimumUint(name, in string, min uint64, exclusive bool, value interface{}) *Validation {
433 var message string
434 if in == "" {
435 m := minIncFailNoIn
436 if exclusive {
437 m = minExcFailNoIn
438 }
439 message = fmt.Sprintf(m, name, min)
440 } else {
441 m := minIncFail
442 if exclusive {
443 m = minExcFail
444 }
445 message = fmt.Sprintf(m, name, in, min)
446 }
447 return &Validation{
448 code: MinFailCode,
449 Name: name,
450 In: in,
451 Value: value,
452 message: message,
453 }
454 }
455
456
457 func ExceedsMinimum(name, in string, min float64, exclusive bool, value interface{}) *Validation {
458 var message string
459 if in == "" {
460 m := minIncFailNoIn
461 if exclusive {
462 m = minExcFailNoIn
463 }
464 message = fmt.Sprintf(m, name, min)
465 } else {
466 m := minIncFail
467 if exclusive {
468 m = minExcFail
469 }
470 message = fmt.Sprintf(m, name, in, min)
471 }
472 return &Validation{
473 code: MinFailCode,
474 Name: name,
475 In: in,
476 Value: value,
477 message: message,
478 }
479 }
480
481
482 func NotMultipleOf(name, in string, multiple, value interface{}) *Validation {
483 var msg string
484 if in == "" {
485 msg = fmt.Sprintf(multipleOfFailNoIn, name, multiple)
486 } else {
487 msg = fmt.Sprintf(multipleOfFail, name, in, multiple)
488 }
489 return &Validation{
490 code: MultipleOfFailCode,
491 Name: name,
492 In: in,
493 Value: value,
494 message: msg,
495 }
496 }
497
498
499 func EnumFail(name, in string, value interface{}, values []interface{}) *Validation {
500 var msg string
501 if in == "" {
502 msg = fmt.Sprintf(enumFailNoIn, name, values)
503 } else {
504 msg = fmt.Sprintf(enumFail, name, in, values)
505 }
506
507 return &Validation{
508 code: EnumFailCode,
509 Name: name,
510 In: in,
511 Value: value,
512 Values: values,
513 message: msg,
514 }
515 }
516
517
518 func Required(name, in string, value interface{}) *Validation {
519 var msg string
520 if in == "" {
521 msg = fmt.Sprintf(requiredFailNoIn, name)
522 } else {
523 msg = fmt.Sprintf(requiredFail, name, in)
524 }
525 return &Validation{
526 code: RequiredFailCode,
527 Name: name,
528 In: in,
529 Value: value,
530 message: msg,
531 }
532 }
533
534
535 func ReadOnly(name, in string, value interface{}) *Validation {
536 var msg string
537 if in == "" {
538 msg = fmt.Sprintf(readOnlyFailNoIn, name)
539 } else {
540 msg = fmt.Sprintf(readOnlyFail, name, in)
541 }
542 return &Validation{
543 code: ReadOnlyFailCode,
544 Name: name,
545 In: in,
546 Value: value,
547 message: msg,
548 }
549 }
550
551
552 func TooLong(name, in string, max int64, value interface{}) *Validation {
553 var msg string
554 if in == "" {
555 msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
556 } else {
557 msg = fmt.Sprintf(tooLongMessage, name, in, max)
558 }
559 return &Validation{
560 code: TooLongFailCode,
561 Name: name,
562 In: in,
563 Value: value,
564 message: msg,
565 }
566 }
567
568
569 func TooShort(name, in string, min int64, value interface{}) *Validation {
570 var msg string
571 if in == "" {
572 msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
573 } else {
574 msg = fmt.Sprintf(tooShortMessage, name, in, min)
575 }
576
577 return &Validation{
578 code: TooShortFailCode,
579 Name: name,
580 In: in,
581 Value: value,
582 message: msg,
583 }
584 }
585
586
587
588 func FailedPattern(name, in, pattern string, value interface{}) *Validation {
589 var msg string
590 if in == "" {
591 msg = fmt.Sprintf(patternFailNoIn, name, pattern)
592 } else {
593 msg = fmt.Sprintf(patternFail, name, in, pattern)
594 }
595
596 return &Validation{
597 code: PatternFailCode,
598 Name: name,
599 In: in,
600 Value: value,
601 message: msg,
602 }
603 }
604
605
606
607 func MultipleOfMustBePositive(name, in string, factor interface{}) *Validation {
608 return &Validation{
609 code: MultipleOfMustBePositiveCode,
610 Name: name,
611 In: in,
612 Value: factor,
613 message: fmt.Sprintf(multipleOfMustBePositive, name, factor),
614 }
615 }
616
View as plain text