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