github.com/jdolitsky/cnab-go@v0.7.1-beta1/bundle/definition/validation.go (about)

     1  package definition
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/pkg/errors"
     7  )
     8  
     9  // ValidationError error represents a validation error
    10  // against the JSON Schema. The type includes the path
    11  // in the given object and the error message
    12  type ValidationError struct {
    13  	Path  string
    14  	Error string
    15  }
    16  
    17  // Validate applies JSON Schema validation to the data passed as a parameter.
    18  // If validation errors occur, they will be returned in as a slice of ValidationError
    19  // structs. If any other error occurs, it will be returned as a separate error
    20  func (s *Schema) Validate(data interface{}) ([]ValidationError, error) {
    21  
    22  	b, err := json.Marshal(s)
    23  	if err != nil {
    24  		return nil, errors.Wrap(err, "unable to load schema")
    25  	}
    26  	def := NewRootSchema()
    27  	err = json.Unmarshal([]byte(b), def)
    28  	if err != nil {
    29  		return nil, errors.Wrap(err, "unable to build schema")
    30  	}
    31  	payload, err := json.Marshal(data)
    32  	if err != nil {
    33  		return nil, errors.Wrap(err, "unable to process data")
    34  	}
    35  	valErrs, err := def.ValidateBytes(payload)
    36  	if err != nil {
    37  		return nil, errors.Wrap(err, "unable to perform validation")
    38  	}
    39  	if len(valErrs) > 0 {
    40  		valErrors := []ValidationError{}
    41  
    42  		for _, err := range valErrs {
    43  			valError := ValidationError{
    44  				Path:  err.PropertyPath,
    45  				Error: err.Message,
    46  			}
    47  			valErrors = append(valErrors, valError)
    48  		}
    49  		return valErrors, nil
    50  	}
    51  	return nil, nil
    52  }
    53  
    54  // CoerceValue can be used to turn float and other numeric types into integers. When
    55  // unmarshaled, often integer values are not represented as an integer. This is a
    56  // convenience method.
    57  func (s *Schema) CoerceValue(value interface{}) interface{} {
    58  	if s.Type == "int" || s.Type == "integer" {
    59  		f, ok := value.(float64)
    60  		if ok {
    61  			i, ok := asInt(f)
    62  			if !ok {
    63  				return f
    64  			}
    65  			return i
    66  		}
    67  	}
    68  	return value
    69  }
    70  
    71  func asInt(f float64) (int, bool) {
    72  	i := int(f)
    73  	if float64(i) != f {
    74  		return 0, false
    75  	}
    76  	return i, true
    77  }