validation.go raw

   1  package smithy
   2  
   3  import (
   4  	"bytes"
   5  	"fmt"
   6  	"strings"
   7  )
   8  
   9  // An InvalidParamsError provides wrapping of invalid parameter errors found when
  10  // validating API operation input parameters.
  11  type InvalidParamsError struct {
  12  	// Context is the base context of the invalid parameter group.
  13  	Context string
  14  	errs    []InvalidParamError
  15  }
  16  
  17  // Add adds a new invalid parameter error to the collection of invalid
  18  // parameters. The context of the invalid parameter will be updated to reflect
  19  // this collection.
  20  func (e *InvalidParamsError) Add(err InvalidParamError) {
  21  	err.SetContext(e.Context)
  22  	e.errs = append(e.errs, err)
  23  }
  24  
  25  // AddNested adds the invalid parameter errors from another InvalidParamsError
  26  // value into this collection. The nested errors will have their nested context
  27  // updated and base context to reflect the merging.
  28  //
  29  // Use for nested validations errors.
  30  func (e *InvalidParamsError) AddNested(nestedCtx string, nested InvalidParamsError) {
  31  	for _, err := range nested.errs {
  32  		err.SetContext(e.Context)
  33  		err.AddNestedContext(nestedCtx)
  34  		e.errs = append(e.errs, err)
  35  	}
  36  }
  37  
  38  // Len returns the number of invalid parameter errors
  39  func (e *InvalidParamsError) Len() int {
  40  	return len(e.errs)
  41  }
  42  
  43  // Error returns the string formatted form of the invalid parameters.
  44  func (e InvalidParamsError) Error() string {
  45  	w := &bytes.Buffer{}
  46  	fmt.Fprintf(w, "%d validation error(s) found.\n", len(e.errs))
  47  
  48  	for _, err := range e.errs {
  49  		fmt.Fprintf(w, "- %s\n", err.Error())
  50  	}
  51  
  52  	return w.String()
  53  }
  54  
  55  // Errs returns a slice of the invalid parameters
  56  func (e InvalidParamsError) Errs() []error {
  57  	errs := make([]error, len(e.errs))
  58  	for i := 0; i < len(errs); i++ {
  59  		errs[i] = e.errs[i]
  60  	}
  61  
  62  	return errs
  63  }
  64  
  65  // An InvalidParamError represents an invalid parameter error type.
  66  type InvalidParamError interface {
  67  	error
  68  
  69  	// Field name the error occurred on.
  70  	Field() string
  71  
  72  	// SetContext updates the context of the error.
  73  	SetContext(string)
  74  
  75  	// AddNestedContext updates the error's context to include a nested level.
  76  	AddNestedContext(string)
  77  }
  78  
  79  type invalidParamError struct {
  80  	context       string
  81  	nestedContext string
  82  	field         string
  83  	reason        string
  84  }
  85  
  86  // Error returns the string version of the invalid parameter error.
  87  func (e invalidParamError) Error() string {
  88  	return fmt.Sprintf("%s, %s.", e.reason, e.Field())
  89  }
  90  
  91  // Field Returns the field and context the error occurred.
  92  func (e invalidParamError) Field() string {
  93  	sb := &strings.Builder{}
  94  	sb.WriteString(e.context)
  95  	if sb.Len() > 0 {
  96  		if len(e.nestedContext) == 0 || (len(e.nestedContext) > 0 && e.nestedContext[:1] != "[") {
  97  			sb.WriteRune('.')
  98  		}
  99  	}
 100  	if len(e.nestedContext) > 0 {
 101  		sb.WriteString(e.nestedContext)
 102  		sb.WriteRune('.')
 103  	}
 104  	sb.WriteString(e.field)
 105  	return sb.String()
 106  }
 107  
 108  // SetContext updates the base context of the error.
 109  func (e *invalidParamError) SetContext(ctx string) {
 110  	e.context = ctx
 111  }
 112  
 113  // AddNestedContext prepends a context to the field's path.
 114  func (e *invalidParamError) AddNestedContext(ctx string) {
 115  	if len(e.nestedContext) == 0 {
 116  		e.nestedContext = ctx
 117  		return
 118  	}
 119  	// Check if our nested context is an index into a slice or map
 120  	if e.nestedContext[:1] != "[" {
 121  		e.nestedContext = fmt.Sprintf("%s.%s", ctx, e.nestedContext)
 122  		return
 123  	}
 124  	e.nestedContext = ctx + e.nestedContext
 125  }
 126  
 127  // An ParamRequiredError represents an required parameter error.
 128  type ParamRequiredError struct {
 129  	invalidParamError
 130  }
 131  
 132  // NewErrParamRequired creates a new required parameter error.
 133  func NewErrParamRequired(field string) *ParamRequiredError {
 134  	return &ParamRequiredError{
 135  		invalidParamError{
 136  			field:  field,
 137  			reason: fmt.Sprintf("missing required field"),
 138  		},
 139  	}
 140  }
 141