...

Source file src/github.com/go-openapi/errors/schema.go

Documentation: github.com/go-openapi/errors

     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  	"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  // All code responses can be used to differentiate errors for different handling
    73  // by the consuming program
    74  const (
    75  	// CompositeErrorCode remains 422 for backwards-compatibility
    76  	// and to separate it from validation errors with cause
    77  	CompositeErrorCode = 422
    78  	// InvalidTypeCode is used for any subclass of invalid types
    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  // CompositeError is an error that groups several errors together
   101  type CompositeError struct {
   102  	Errors  []error
   103  	code    int32
   104  	message string
   105  }
   106  
   107  // Code for this error
   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  // MarshalJSON implements the JSON encoding interface
   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  // CompositeValidationError an error to wrap a bunch of other errors
   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  // ValidateName recursively sets the name for all validations or updates them for nested properties
   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  // FailedAllPatternProperties an error for when the property doesn't match a pattern
   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  // PropertyNotAllowed an error for when the property doesn't match a pattern
   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  // TooFewProperties an error for an object with too few properties
   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  // TooManyProperties an error for an object with too many properties
   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  // AdditionalItemsNotAllowed an error for invalid additional items
   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  // InvalidCollectionFormat another flavor of invalid type error
   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  // InvalidTypeName an error for when the type is invalid
   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  // InvalidType creates an error for when the type is invalid
   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  // DuplicateItems error for when an array contains duplicates
   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  // TooManyItems error for when an array contains too many items
   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  // TooFewItems error for when an array contains too few items
   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  // ExceedsMaximumInt error for when maximum validation fails
   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  // ExceedsMaximumUint error for when maximum validation fails
   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  // ExceedsMaximum error for when maximum validation fails
   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  // ExceedsMinimumInt error for when minimum validation fails
   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  // ExceedsMinimumUint error for when minimum validation fails
   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  // ExceedsMinimum error for when minimum validation fails
   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  // NotMultipleOf error for when multiple of validation fails
   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  // EnumFail error for when an enum validation fails
   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  // Required error for when a value is missing
   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  // ReadOnly error for when a value is present in request
   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  // TooLong error for when a string is too long
   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  // TooShort error for when a string is too short
   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  // FailedPattern error for when a string fails a regex pattern match
   587  // the pattern that is returned is the ECMA syntax version of the pattern not the golang version.
   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  // MultipleOfMustBePositive error for when a
   606  // multipleOf factor is negative
   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