k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/validation/errors/schema.go (about)

     1  // 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  
    15  package errors
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  )
    21  
    22  const (
    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
    71  const (
    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
    97  type CompositeError struct {
    98  	Errors  []error
    99  	code    int32
   100  	message string
   101  }
   102  
   103  // Code for this error
   104  func (c *CompositeError) Code() int32 {
   105  	return c.code
   106  }
   107  
   108  func (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
   120  func 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
   129  func 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
   144  func 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
   159  func TooFewProperties(name, in string, minProperties, size int64) *Validation {
   160  	msg := fmt.Sprintf(tooFewProperties, name, in, minProperties)
   161  	if in == "" {
   162  		msg = fmt.Sprintf(tooFewPropertiesNoIn, name, minProperties)
   163  	}
   164  	return &Validation{
   165  		code:    TooFewPropertiesCode,
   166  		Name:    name,
   167  		In:      in,
   168  		Value:   size,
   169  		Valid:   minProperties,
   170  		message: msg,
   171  	}
   172  }
   173  
   174  // TooManyProperties an error for an object with too many properties
   175  func TooManyProperties(name, in string, maxProperties, size int64) *Validation {
   176  	msg := fmt.Sprintf(tooManyProperties, name, in, maxProperties)
   177  	if in == "" {
   178  		msg = fmt.Sprintf(tooManyPropertiesNoIn, name, maxProperties)
   179  	}
   180  	return &Validation{
   181  		code:    TooManyPropertiesCode,
   182  		Name:    name,
   183  		In:      in,
   184  		Value:   size,
   185  		Valid:   maxProperties,
   186  		message: msg,
   187  	}
   188  }
   189  
   190  // AdditionalItemsNotAllowed an error for invalid additional items
   191  func AdditionalItemsNotAllowed(name, in string) *Validation {
   192  	msg := fmt.Sprintf(noAdditionalItems, name, in)
   193  	if in == "" {
   194  		msg = fmt.Sprintf(noAdditionalItemsNoIn, name)
   195  	}
   196  	return &Validation{
   197  		code:    NoAdditionalItemsCode,
   198  		Name:    name,
   199  		In:      in,
   200  		message: msg,
   201  	}
   202  }
   203  
   204  // InvalidCollectionFormat another flavor of invalid type error
   205  func InvalidCollectionFormat(name, in, format string) *Validation {
   206  	return &Validation{
   207  		code:    InvalidTypeCode,
   208  		Name:    name,
   209  		In:      in,
   210  		Value:   format,
   211  		message: fmt.Sprintf("the collection format %q is not supported for the %s param %q", format, in, name),
   212  	}
   213  }
   214  
   215  // InvalidTypeName an error for when the type is invalid
   216  func InvalidTypeName(typeName string) *Validation {
   217  	return &Validation{
   218  		code:    InvalidTypeCode,
   219  		Value:   typeName,
   220  		message: fmt.Sprintf(invalidType, typeName),
   221  	}
   222  }
   223  
   224  // InvalidType creates an error for when the type is invalid
   225  func InvalidType(name, in, typeName string, value interface{}) *Validation {
   226  	var message string
   227  
   228  	if in != "" {
   229  		switch value.(type) {
   230  		case string:
   231  			message = fmt.Sprintf(typeFailWithData, name, in, typeName, value)
   232  		case error:
   233  			message = fmt.Sprintf(typeFailWithError, name, in, typeName, value)
   234  		default:
   235  			message = fmt.Sprintf(typeFail, name, in, typeName)
   236  		}
   237  	} else {
   238  		switch value.(type) {
   239  		case string:
   240  			message = fmt.Sprintf(typeFailWithDataNoIn, name, typeName, value)
   241  		case error:
   242  			message = fmt.Sprintf(typeFailWithErrorNoIn, name, typeName, value)
   243  		default:
   244  			message = fmt.Sprintf(typeFailNoIn, name, typeName)
   245  		}
   246  	}
   247  
   248  	return &Validation{
   249  		code:    InvalidTypeCode,
   250  		Name:    name,
   251  		In:      in,
   252  		Value:   value,
   253  		message: message,
   254  	}
   255  
   256  }
   257  
   258  // DuplicateItems error for when an array contains duplicates
   259  func DuplicateItems(name, in string) *Validation {
   260  	msg := fmt.Sprintf(uniqueFail, name, in)
   261  	if in == "" {
   262  		msg = fmt.Sprintf(uniqueFailNoIn, name)
   263  	}
   264  	return &Validation{
   265  		code:    UniqueFailCode,
   266  		Name:    name,
   267  		In:      in,
   268  		message: msg,
   269  	}
   270  }
   271  
   272  // TooManyItems error for when an array contains too many items
   273  func TooManyItems(name, in string, max int64, value interface{}) *Validation {
   274  	msg := fmt.Sprintf(maxItemsFail, name, in, max)
   275  	if in == "" {
   276  		msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
   277  	}
   278  
   279  	return &Validation{
   280  		code:    MaxItemsFailCode,
   281  		Name:    name,
   282  		In:      in,
   283  		Value:   value,
   284  		Valid:   max,
   285  		message: msg,
   286  	}
   287  }
   288  
   289  // TooFewItems error for when an array contains too few items
   290  func TooFewItems(name, in string, min int64, value interface{}) *Validation {
   291  	msg := fmt.Sprintf(minItemsFail, name, in, min)
   292  	if in == "" {
   293  		msg = fmt.Sprintf(minItemsFailNoIn, name, min)
   294  	}
   295  	return &Validation{
   296  		code:    MinItemsFailCode,
   297  		Name:    name,
   298  		In:      in,
   299  		Value:   value,
   300  		Valid:   min,
   301  		message: msg,
   302  	}
   303  }
   304  
   305  // ExceedsMaximumInt error for when maxinum validation fails
   306  func ExceedsMaximumInt(name, in string, max int64, exclusive bool, value interface{}) *Validation {
   307  	var message string
   308  	if in == "" {
   309  		m := maxIncFailNoIn
   310  		if exclusive {
   311  			m = maxExcFailNoIn
   312  		}
   313  		message = fmt.Sprintf(m, name, max)
   314  	} else {
   315  		m := maxIncFail
   316  		if exclusive {
   317  			m = maxExcFail
   318  		}
   319  		message = fmt.Sprintf(m, name, in, max)
   320  	}
   321  	return &Validation{
   322  		code:    MaxFailCode,
   323  		Name:    name,
   324  		In:      in,
   325  		Value:   value,
   326  		message: message,
   327  	}
   328  }
   329  
   330  // ExceedsMaximumUint error for when maxinum validation fails
   331  func ExceedsMaximumUint(name, in string, max uint64, exclusive bool, value interface{}) *Validation {
   332  	var message string
   333  	if in == "" {
   334  		m := maxIncFailNoIn
   335  		if exclusive {
   336  			m = maxExcFailNoIn
   337  		}
   338  		message = fmt.Sprintf(m, name, max)
   339  	} else {
   340  		m := maxIncFail
   341  		if exclusive {
   342  			m = maxExcFail
   343  		}
   344  		message = fmt.Sprintf(m, name, in, max)
   345  	}
   346  	return &Validation{
   347  		code:    MaxFailCode,
   348  		Name:    name,
   349  		In:      in,
   350  		Value:   value,
   351  		message: message,
   352  	}
   353  }
   354  
   355  // ExceedsMaximum error for when maxinum validation fails
   356  func ExceedsMaximum(name, in string, max float64, exclusive bool, value interface{}) *Validation {
   357  	var message string
   358  	if in == "" {
   359  		m := maxIncFailNoIn
   360  		if exclusive {
   361  			m = maxExcFailNoIn
   362  		}
   363  		message = fmt.Sprintf(m, name, max)
   364  	} else {
   365  		m := maxIncFail
   366  		if exclusive {
   367  			m = maxExcFail
   368  		}
   369  		message = fmt.Sprintf(m, name, in, max)
   370  	}
   371  	return &Validation{
   372  		code:    MaxFailCode,
   373  		Name:    name,
   374  		In:      in,
   375  		Value:   value,
   376  		message: message,
   377  	}
   378  }
   379  
   380  // ExceedsMinimumInt error for when maxinum validation fails
   381  func ExceedsMinimumInt(name, in string, min int64, exclusive bool, value interface{}) *Validation {
   382  	var message string
   383  	if in == "" {
   384  		m := minIncFailNoIn
   385  		if exclusive {
   386  			m = minExcFailNoIn
   387  		}
   388  		message = fmt.Sprintf(m, name, min)
   389  	} else {
   390  		m := minIncFail
   391  		if exclusive {
   392  			m = minExcFail
   393  		}
   394  		message = fmt.Sprintf(m, name, in, min)
   395  	}
   396  	return &Validation{
   397  		code:    MinFailCode,
   398  		Name:    name,
   399  		In:      in,
   400  		Value:   value,
   401  		message: message,
   402  	}
   403  }
   404  
   405  // ExceedsMinimumUint error for when maxinum validation fails
   406  func ExceedsMinimumUint(name, in string, min uint64, exclusive bool, value interface{}) *Validation {
   407  	var message string
   408  	if in == "" {
   409  		m := minIncFailNoIn
   410  		if exclusive {
   411  			m = minExcFailNoIn
   412  		}
   413  		message = fmt.Sprintf(m, name, min)
   414  	} else {
   415  		m := minIncFail
   416  		if exclusive {
   417  			m = minExcFail
   418  		}
   419  		message = fmt.Sprintf(m, name, in, min)
   420  	}
   421  	return &Validation{
   422  		code:    MinFailCode,
   423  		Name:    name,
   424  		In:      in,
   425  		Value:   value,
   426  		message: message,
   427  	}
   428  }
   429  
   430  // ExceedsMinimum error for when maxinum validation fails
   431  func ExceedsMinimum(name, in string, min float64, exclusive bool, value interface{}) *Validation {
   432  	var message string
   433  	if in == "" {
   434  		m := minIncFailNoIn
   435  		if exclusive {
   436  			m = minExcFailNoIn
   437  		}
   438  		message = fmt.Sprintf(m, name, min)
   439  	} else {
   440  		m := minIncFail
   441  		if exclusive {
   442  			m = minExcFail
   443  		}
   444  		message = fmt.Sprintf(m, name, in, min)
   445  	}
   446  	return &Validation{
   447  		code:    MinFailCode,
   448  		Name:    name,
   449  		In:      in,
   450  		Value:   value,
   451  		message: message,
   452  	}
   453  }
   454  
   455  // NotMultipleOf error for when multiple of validation fails
   456  func NotMultipleOf(name, in string, multiple, value interface{}) *Validation {
   457  	var msg string
   458  	if in == "" {
   459  		msg = fmt.Sprintf(multipleOfFailNoIn, name, multiple)
   460  	} else {
   461  		msg = fmt.Sprintf(multipleOfFail, name, in, multiple)
   462  	}
   463  	return &Validation{
   464  		code:    MultipleOfFailCode,
   465  		Name:    name,
   466  		In:      in,
   467  		Value:   value,
   468  		message: msg,
   469  	}
   470  }
   471  
   472  // EnumFail error for when an enum validation fails
   473  func EnumFail(name, in string, value interface{}, values []interface{}) *Validation {
   474  	var msg string
   475  	if in == "" {
   476  		msg = fmt.Sprintf(enumFailNoIn, name, values)
   477  	} else {
   478  		msg = fmt.Sprintf(enumFail, name, in, values)
   479  	}
   480  
   481  	return &Validation{
   482  		code:    EnumFailCode,
   483  		Name:    name,
   484  		In:      in,
   485  		Value:   value,
   486  		Values:  values,
   487  		message: msg,
   488  	}
   489  }
   490  
   491  // Required error for when a value is missing
   492  func Required(name, in string) *Validation {
   493  	var msg string
   494  	if in == "" {
   495  		msg = fmt.Sprintf(requiredFailNoIn, name)
   496  	} else {
   497  		msg = fmt.Sprintf(requiredFail, name, in)
   498  	}
   499  	return &Validation{
   500  		code:    RequiredFailCode,
   501  		Name:    name,
   502  		In:      in,
   503  		message: msg,
   504  	}
   505  }
   506  
   507  // TooLong error for when a string is too long
   508  func TooLong(name, in string, max int64, value interface{}) *Validation {
   509  	var msg string
   510  	if in == "" {
   511  		msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
   512  	} else {
   513  		msg = fmt.Sprintf(tooLongMessage, name, in, max)
   514  	}
   515  	return &Validation{
   516  		code:    TooLongFailCode,
   517  		Name:    name,
   518  		In:      in,
   519  		Value:   value,
   520  		Valid:   max,
   521  		message: msg,
   522  	}
   523  }
   524  
   525  // TooShort error for when a string is too short
   526  func TooShort(name, in string, min int64, value interface{}) *Validation {
   527  	var msg string
   528  	if in == "" {
   529  		msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
   530  	} else {
   531  		msg = fmt.Sprintf(tooShortMessage, name, in, min)
   532  	}
   533  
   534  	return &Validation{
   535  		code:    TooShortFailCode,
   536  		Name:    name,
   537  		In:      in,
   538  		Value:   value,
   539  		Valid:   min,
   540  		message: msg,
   541  	}
   542  }
   543  
   544  // FailedPattern error for when a string fails a regex pattern match
   545  // the pattern that is returned is the ECMA syntax version of the pattern not the golang version.
   546  func FailedPattern(name, in, pattern string, value interface{}) *Validation {
   547  	var msg string
   548  	if in == "" {
   549  		msg = fmt.Sprintf(patternFailNoIn, name, pattern)
   550  	} else {
   551  		msg = fmt.Sprintf(patternFail, name, in, pattern)
   552  	}
   553  
   554  	return &Validation{
   555  		code:    PatternFailCode,
   556  		Name:    name,
   557  		In:      in,
   558  		Value:   value,
   559  		message: msg,
   560  	}
   561  }
   562  
   563  // MultipleOfMustBePositive error for when a
   564  // multipleOf factor is negative
   565  func MultipleOfMustBePositive(name, in string, factor interface{}) *Validation {
   566  	return &Validation{
   567  		code:    MultipleOfMustBePositiveCode,
   568  		Name:    name,
   569  		In:      in,
   570  		Value:   factor,
   571  		message: fmt.Sprintf(multipleOfMustBePositive, name, factor),
   572  	}
   573  }